daemon/Win32: Implement statvfs using GetDiskFreeSpaceEx.
authorRichard Jones <rjones@redhat.com>
Wed, 25 Nov 2009 13:07:05 +0000 (13:07 +0000)
committerRichard Jones <rjones@redhat.com>
Wed, 25 Nov 2009 16:28:26 +0000 (16:28 +0000)
At the time of writing Gnulib didn't support Win32 for its
fsusage API.  Therefore this patch uses GetDiskFreeSpaceEx
if it's available (on Windows) otherwise falls back to using
Gnulib fsusage.

daemon/.gitignore
daemon/configure.ac
daemon/m4/gnulib-cache.m4
daemon/statvfs.c

index 9168142..0cc1e13 100644 (file)
@@ -30,6 +30,7 @@ m4/fcntl_h.m4
 m4/fdopendir.m4
 m4/float_h.m4
 m4/fnmatch.m4
+m4/fsusage.m4
 m4/futimens.m4
 m4/getcwd-abort-bug.m4
 m4/getcwd-path-max.m4
@@ -91,6 +92,8 @@ m4/rawmemchr.m4
 m4/readlink.m4
 m4/realloc.m4
 m4/rmdir.m4
+m4/safe-read.m4
+m4/safe-write.m4
 m4/save-cwd.m4
 m4/select.m4
 m4/size_max.m4
@@ -98,6 +101,7 @@ m4/sleep.m4
 m4/sockets.m4
 m4/socklen.m4
 m4/sockpfaf.m4
+m4/ssize_t.m4
 m4/stat-time.m4
 m4/stat.m4
 m4/stdbool.m4
@@ -139,6 +143,7 @@ m4/wchar_t.m4
 m4/wctob.m4
 m4/wctype.m4
 m4/wint_t.m4
+m4/write.m4
 m4/xalloc.m4
 m4/xgetcwd.m4
 m4/xsize.m4
index c7025dd..bd0bdbe 100644 (file)
@@ -181,6 +181,7 @@ AC_CHECK_FUNCS([\
         posix_fallocate \
         removexattr \
         setxattr \
+        statvfs \
         sync])
 
 dnl Headers.
@@ -188,6 +189,7 @@ AC_CHECK_HEADERS([\
         attr/xattr.h \
         printf.h \
         sys/inotify.h \
+        sys/statvfs.h \
         sys/xattr.h \
         windows.h])
 
index 2b63258..a9b19e9 100644 (file)
 
 
 # Specification in the form of a command-line invocation:
-#   gnulib-tool --import --dir=. --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --with-tests --no-libtool --macro-prefix=gl c-ctype futimens getline glob hash ignore-value manywarnings mkdtemp netdb openat readlink select sleep strchrnul strndup sys_select sys_wait vasprintf warnings
+#   gnulib-tool --import --dir=. --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --with-tests --no-libtool --macro-prefix=gl c-ctype fsusage futimens getline glob hash ignore-value manywarnings mkdtemp netdb openat readlink select sleep strchrnul strndup sys_select sys_wait vasprintf warnings
 
 # Specification in the form of a few gnulib-tool.m4 macro invocations:
 gl_LOCAL_DIR([])
 gl_MODULES([
   c-ctype
+  fsusage
   futimens
   getline
   glob
index 40df9b9..e71b19a 100644 (file)
 
 #include <config.h>
 
+#ifdef HAVE_WINDOWS_H
+#include <windows.h>
+#endif
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/types.h>
-#include <sys/statvfs.h>
 #include <fcntl.h>
 #include <unistd.h>
 
+#ifdef HAVE_SYS_STATVFS_H
+#include <sys/statvfs.h>
+#endif
+
+#include <fsusage.h>
+
 #include "../src/guestfs_protocol.h"
 #include "daemon.h"
 #include "actions.h"
@@ -33,6 +42,7 @@
 guestfs_int_statvfs *
 do_statvfs (const char *path)
 {
+#ifdef HAVE_STATVFS
   int r;
   guestfs_int_statvfs *ret;
   struct statvfs statbuf;
@@ -65,4 +75,112 @@ do_statvfs (const char *path)
   ret->namemax = statbuf.f_namemax;
 
   return ret;
+
+#else /* !HAVE_STATVFS */
+#  if WIN32
+
+  char *disk;
+  guestfs_int_statvfs *ret;
+  ULONGLONG free_bytes_available; /* for user - similar to bavail */
+  ULONGLONG total_number_of_bytes;
+  ULONGLONG total_number_of_free_bytes; /* for everyone - bfree */
+
+  disk = sysroot_path (path);
+  if (!disk) {
+    reply_with_perror ("malloc");
+    return NULL;
+  }
+
+  if (!GetDiskFreeSpaceEx (disk,
+                           (PULARGE_INTEGER) &free_bytes_available,
+                           (PULARGE_INTEGER) &total_number_of_bytes,
+                           (PULARGE_INTEGER) &total_number_of_free_bytes)) {
+    reply_with_perror ("GetDiskFreeSpaceEx");
+    free (disk);
+    return NULL;
+  }
+  free (disk);
+
+  ret = malloc (sizeof *ret);
+  if (ret == NULL) {
+    reply_with_perror ("malloc");
+    return NULL;
+  }
+
+  /* XXX I couldn't determine how to get block size.  MSDN has a
+   * unhelpful hard-coded list here:
+   *   http://support.microsoft.com/kb/140365
+   * but this depends on the filesystem type, the size of the disk and
+   * the version of Windows.  So this code assumes the disk is NTFS
+   * and the version of Windows is >= Win2K.
+   */
+  if (total_number_of_bytes < 16ULL * 1024 * 1024 * 1024 * 1024)
+    ret->bsize = 4096;
+  else if (total_number_of_bytes < 32ULL * 1024 * 1024 * 1024 * 1024)
+    ret->bsize = 8192;
+  else if (total_number_of_bytes < 64ULL * 1024 * 1024 * 1024 * 1024)
+    ret->bsize = 16384;
+  else if (total_number_of_bytes < 128ULL * 1024 * 1024 * 1024 * 1024)
+    ret->bsize = 32768;
+  else
+    ret->bsize = 65536;
+
+  /* As with stat, -1 indicates a field is not known. */
+  ret->frsize = ret->bsize;
+  ret->blocks = total_number_of_bytes / ret->bsize;
+  ret->bfree = total_number_of_free_bytes / ret->bsize;
+  ret->bavail = free_bytes_available / ret->bsize;
+  ret->files = -1;
+  ret->ffree = -1;
+  ret->favail = -1;
+  ret->fsid = -1;
+  ret->flag = -1;
+  ret->namemax = FILENAME_MAX;
+
+  return ret;
+
+#  else /* !WIN32 */
+
+  char *disk;
+  int r;
+  guestfs_int_statvfs *ret;
+  struct fs_usage fsu;
+
+  disk = sysroot_path (path);
+  if (!disk) {
+    reply_with_perror ("malloc");
+    return NULL;
+  }
+
+  r = get_fs_usage (disk, disk, &fsu);
+  free (disk);
+
+  if (r == -1) {
+    reply_with_perror ("get_fs_usage: %s", path);
+    return NULL;
+  }
+
+  ret = malloc (sizeof *ret);
+  if (ret == NULL) {
+    reply_with_perror ("malloc");
+    return NULL;
+  }
+
+  /* As with stat, -1 indicates a field is not known. */
+  ret->bsize = fsu.f_bsize;
+  ret->frsize = -1;
+  ret->blocks = fsu.f_blocks;
+  ret->bfree = fsu.f_bfree;
+  ret->bavail = fsu.f_bavail;
+  ret->files = fsu.f_files;
+  ret->ffree = fsu.f_ffree;
+  ret->favail = -1;
+  ret->fsid = -1;
+  ret->flag = -1;
+  ret->namemax = -1;
+
+  return ret;
+
+#  endif /* !WIN32 */
+#endif /* !HAVE_STATVFS */
 }