sync: Windows implementation of sync() call.
authorRichard Jones <rjones@redhat.com>
Wed, 25 Nov 2009 10:26:48 +0000 (10:26 +0000)
committerRichard Jones <rjones@redhat.com>
Wed, 25 Nov 2009 16:28:26 +0000 (16:28 +0000)
Replace calls to sync() with calls to sync_disks() which supports
Win32 via FlushFileBuffers.

daemon/configure.ac
daemon/daemon.h
daemon/dropcaches.c
daemon/sync.c

index 7bcdd7e..d1a9b0f 100644 (file)
@@ -181,14 +181,16 @@ AC_CHECK_FUNCS([\
         mknod \
         posix_fallocate \
         removexattr \
-        setxattr])
+        setxattr \
+        sync])
 
 dnl Headers.
 AC_CHECK_HEADERS([\
-       attr/xattr.h \
-       printf.h \
-       sys/inotify.h \
-       sys/xattr.h])
+        attr/xattr.h \
+        printf.h \
+        sys/inotify.h \
+        sys/xattr.h \
+        windows.h])
 
 dnl For modified printf, we need glibc either (old-style)
 dnl register_printf_function or (new-style) register_printf_specifier.
index 7ba7599..6872bd7 100644 (file)
@@ -112,6 +112,10 @@ struct optgroup {
 };
 extern struct optgroup optgroups[];
 
+/*-- in sync.c --*/
+/* Use this as a replacement for sync(2). */
+extern int sync_disks (void);
+
 /* ordinary daemon functions use these to indicate errors */
 extern void reply_with_error (const char *fs, ...)
   __attribute__((format (printf,1,2)));
index a818323..46bfd07 100644 (file)
@@ -34,7 +34,10 @@ do_drop_caches (int what)
 {
   FILE *fp;
 
-  sync ();
+  if (sync_disks () == -1) {
+    reply_with_perror ("sync");
+    return -1;
+  }
 
   fp = fopen (PROCFILE, "w");
   if (fp == NULL) {
index e96bf03..2cdb10c 100644 (file)
 
 #include <config.h>
 
+#ifdef HAVE_WINDOWS_H
+#include <windows.h>
+#endif
+
 #include <stdio.h>
 #include <unistd.h>
 
+#include "daemon.h"
 #include "actions.h"
 
+#ifdef WIN32
+static int sync_win32 (void);
+#endif
+
 int
 do_sync (void)
 {
-  sync ();
+  if (sync_disks () == -1) {
+    reply_with_perror ("sync");
+    return -1;
+  }
+
+  return 0;
+}
+
+/* This is a replacement for sync(2) which is called from
+ * this file and from other places in the daemon.  It works
+ * on Windows too.
+ */
+int
+sync_disks (void)
+{
+#if defined(HAVE_SYNC)
+  return sync ();
+#elif defined(WIN32)
+  return sync_win32 ();
+#else
+#error "no known sync() API"
+#endif
+}
+
+#ifdef WIN32
+static int
+sync_win32 (void)
+{
+  DWORD n1, n2;
+
+  n1 = GetLogicalDriveStrings (0, NULL);
+  if (n1 == 0)
+    return -1;
+
+  TCHAR buffer[n1+2]; /* sic */
+  n2 = GetLogicalDriveStrings (n1, buffer);
+  if (n2 == 0)
+    return -1;
+
+  TCHAR *p = buffer;
+
+  /* The MSDN example code itself assumes that there is always one
+   * drive in the system.  However we will be better than that and not
+   * make the assumption ...
+   */
+  while (*p) {
+    HANDLE drive;
+    DWORD drive_type;
+
+    if (verbose)
+      fprintf (stderr, "sync_win32: examining drive %s\n", p);
+
+    /* Ignore removable drives. */
+    drive_type = GetDriveType (p);
+    if (drive_type == DRIVE_FIXED) {
+      /* To open the volume you have to specify the volume name, not
+       * the mount point.  MSDN documents use of the constant 50
+       * below.
+       */
+      TCHAR volname[50];
+      if (!GetVolumeNameForVolumeMountPoint (p, volname, 50))
+       return -1;
+
+      drive = CreateFile (volname, GENERIC_READ|GENERIC_WRITE,
+                          FILE_SHARE_READ|FILE_SHARE_WRITE,
+                          NULL, OPEN_EXISTING, 0, 0);
+      if (drive == INVALID_HANDLE_VALUE)
+        return -1;
+      if (verbose)
+        fprintf (stderr, "sync_win32: flushing %s\n", volname);
+
+      BOOL r;
+      /* This always fails in Wine:
+       * http://bugs.winehq.org/show_bug.cgi?id=14915
+       */
+      r = FlushFileBuffers (drive);
+      CloseHandle (drive);
+      if (!r)
+        return -1;
+    }
+
+    /* Skip to next \0 character. */
+    while (*p++);
+  }
+
   return 0;
 }
+#endif /* WIN32 */