[Libvir] PATCH: 11/16: directory/fs/netfs backend

Daniel P. Berrange berrange at redhat.com
Wed Feb 20 04:03:56 UTC 2008


On Tue, Feb 12, 2008 at 04:37:57AM +0000, Daniel P. Berrange wrote:
> This patch implements 3 storage pools in one go. This provides
> the base level 'directory' storage pool, where an existing directory
> contains files as volumes. This is guarenteed to be available on
> any OS since it just uses plain POSIX apis for creation/deletion.
> If qemu-img or qcow2-create command line tools are available it
> can also create various non-raw fileformats such as QCow2, VMDK.
> If the mount/unmount commands are available, the 'fs' and 'netfs'
> pools become available. This allow a local disk, or remote filesystem
> to be mounted on the local filesystem, and files managed within.
> This driver contains code for probing the non-raw file formats to
> determine their logical capacity.

 b/docs/storage/pool-dir.xml   |    6 
 b/docs/storage/pool-fs.xml    |   15 
 b/docs/storage/pool-netfs.xml |   16 
 b/docs/storage/vol-cow.xml    |   10 
 b/docs/storage/vol-qcow.xml   |   10 
 b/docs/storage/vol-qcow2.xml  |   10 
 b/docs/storage/vol-raw.xml    |    7 
 b/docs/storage/vol-sparse.xml |    7 
 b/docs/storage/vol-vmdk.xml   |   10 
 b/src/storage_backend_fs.c    | 1123 ++++++++++++++++++++++++++++++++++++++++++
 b/src/storage_backend_fs.h    |   49 +
 configure.in                  |   52 +
 libvirt.spec.in               |   24 
 po/POTFILES.in                |    1 
 src/Makefile.am               |    1 
 src/storage_backend.c         |   34 +
 16 files changed, 1375 insertions(+)



diff -r 686cf593fe28 configure.in
--- a/configure.in	Tue Feb 19 17:04:59 2008 -0500
+++ b/configure.in	Tue Feb 19 17:22:04 2008 -0500
@@ -551,6 +551,52 @@ AC_SUBST(VIRSH_LIBS)
 
 AC_SUBST(WITH_XEN)
 AC_SUBST(LIBVIRT_FEATURES)
+
+
+dnl
+dnl Storage driver checks
+dnl
+
+AC_ARG_WITH(storage-fs,
+[  --with-storage-fs           with FileSystem backend for the storage driver (on)],[],[with_storage_fs=check])
+
+if test "$with_storage_fs" = "yes" -o "$with_storage_fs" = "check"; then
+  AC_PATH_PROG(MOUNT, [mount], [], [$PATH:/sbin:/usr/sbin])
+  AC_PATH_PROG(UMOUNT, [umount], [], [$PATH:/sbin:/usr/sbin])
+  if test "$with_storage_fs" = "yes" ; then
+    if test -z "$MOUNT" ; then AC_MSG_ERROR(We need mount for FS storage driver) ; fi
+    if test -z "$UMOUNT" ; then AC_MSG_ERROR(We need mount for FS storage driver) ; fi
+  else
+    if test -z "$MOUNT" ; then with_storage_fs=no ; fi
+    if test -z "$UMOUNT" ; then with_storage_fs=no ; fi
+
+    if test "$with_storage_fs" = "check" ; then with_storage_fs=yes ; fi
+  fi
+
+  if test "$with_storage_fs" = "yes" ; then
+    AC_DEFINE_UNQUOTED(WITH_STORAGE_FS, 1, [whether FS backend for storage driver is enabled])
+    AC_DEFINE_UNQUOTED([MOUNT],["$MOUNT"],
+        [Location or name of the mount program])
+    AC_DEFINE_UNQUOTED([UMOUNT],["$UMOUNT"],
+        [Location or name of the mount program])
+  fi
+fi
+AM_CONDITIONAL(WITH_STORAGE_FS, [test "$with_storage_fs" = "yes"])
+
+AC_PATH_PROG(QEMU_IMG, [qemu-img], [], [$PATH:/sbin:/usr/sbin:/bin:/usr/bin])
+if test -n "$QEMU_IMG" ; then
+  AC_DEFINE_UNQUOTED(HAVE_QEMU_IMG, 1, [whether qemu-img is available for non-raw files])
+  AC_DEFINE_UNQUOTED([QEMU_IMG],["$QEMU_IMG"],
+      [Location or name of the qemu-img program])
+fi
+
+AC_PATH_PROG(QCOW_CREATE, [qcow-create], [], [$PATH:/sbin:/usr/sbin:/bin:/usr/bin])
+if test -n "$QCOW_CREATE" ; then
+  AC_DEFINE_UNQUOTED(HAVE_QCOW_CREATE, 1, [whether qcow-create is available for non-raw files])
+  AC_DEFINE_UNQUOTED([QCOW_CREATE],["$QCOW_CREATE"],
+      [Location or name of the qcow-create program])
+fi
+
 
 dnl
 dnl check for python
@@ -760,6 +806,12 @@ AC_MSG_NOTICE([  Remote: $with_remote])
 AC_MSG_NOTICE([  Remote: $with_remote])
 AC_MSG_NOTICE([Libvirtd: $with_libvirtd])
 AC_MSG_NOTICE([])
+AC_MSG_NOTICE([Storage Drivers])
+AC_MSG_NOTICE([])
+AC_MSG_NOTICE([     Dir: yes])
+AC_MSG_NOTICE([      FS: $with_storage_fs])
+AC_MSG_NOTICE([   NetFS: $with_storage_fs])
+AC_MSG_NOTICE([])
 AC_MSG_NOTICE([Libraries])
 AC_MSG_NOTICE([])
 AC_MSG_NOTICE([  libxml: $LIBXML_CFLAGS $LIBXML_LIBS])
diff -r 686cf593fe28 docs/storage/pool-dir.xml
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/storage/pool-dir.xml	Tue Feb 19 17:22:04 2008 -0500
@@ -0,0 +1,6 @@
+<pool type="dir">
+  <name>virtimages</name>
+  <target>
+    <path>/var/lib/virt/images</path>
+  </target>
+</pool>
diff -r 686cf593fe28 docs/storage/pool-fs.xml
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/storage/pool-fs.xml	Tue Feb 19 17:22:04 2008 -0500
@@ -0,0 +1,15 @@
+<pool type="fs">
+  <name>virtimages</name>
+  <source>
+    <device path="/dev/VolGroup00/VirtImages"/>
+  </source>
+  <target>
+    <path>/var/lib/virt/images</path>
+    <permissions>
+      <mode>0700</mode>
+      <owner>0</owner>
+      <group>0</group>
+      <label>system_u:object_r:xen_image_t:s0</label>
+    </permissions>
+  </target>
+</pool>
diff -r 686cf593fe28 docs/storage/pool-netfs.xml
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/storage/pool-netfs.xml	Tue Feb 19 17:22:04 2008 -0500
@@ -0,0 +1,16 @@
+<pool type="netfs">
+  <name>virtimages</name>
+  <source>
+    <host name="nfs.example.com"/>
+    <directory path="/var/lib/virt/images"/>
+  </source>
+  <target>
+    <path>/var/lib/virt/images</path>
+    <permissions>
+      <mode>0700</mode>
+      <owner>0</owner>
+      <group>0</group>
+      <label>system_u:object_r:xen_image_t:s0</label>
+    </permissions>
+  </target>
+</pool>
diff -r 686cf593fe28 docs/storage/vol-cow.xml
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/storage/vol-cow.xml	Tue Feb 19 17:22:04 2008 -0500
@@ -0,0 +1,10 @@
+<volume type="file">
+  <name>cow.img</name>
+  <storage>
+    <allocation>0</allocation>
+    <capacity unit="T">1</capacity>
+  </storage>
+  <target>
+    <format type="cow"/>
+  </target>
+</volume>
diff -r 686cf593fe28 docs/storage/vol-qcow.xml
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/storage/vol-qcow.xml	Tue Feb 19 17:22:04 2008 -0500
@@ -0,0 +1,10 @@
+<volume type="file">
+  <name>qcow.img</name>
+  <storage>
+    <allocation>0</allocation>
+    <capacity unit="T">1</capacity>
+  </storage>
+  <target>
+    <format type="qcow"/>
+  </target>
+</volume>
diff -r 686cf593fe28 docs/storage/vol-qcow2.xml
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/storage/vol-qcow2.xml	Tue Feb 19 17:22:04 2008 -0500
@@ -0,0 +1,10 @@
+<volume type="file">
+  <name>qcow2.img</name>
+  <storage>
+    <allocation>0</allocation>
+    <capacity unit="T">1</capacity>
+  </storage>
+  <target>
+    <format type="qcow2"/>
+  </target>
+</volume>
diff -r 686cf593fe28 docs/storage/vol-raw.xml
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/storage/vol-raw.xml	Tue Feb 19 17:22:04 2008 -0500
@@ -0,0 +1,7 @@
+<volume type="file">
+  <name>raw.img</name>
+  <storage>
+    <allocation unit="M">10</allocation>
+    <capacity unit="M">1000</capacity>
+  </storage>
+</volume>
diff -r 686cf593fe28 docs/storage/vol-sparse.xml
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/storage/vol-sparse.xml	Tue Feb 19 17:22:04 2008 -0500
@@ -0,0 +1,7 @@
+<volume type="file">
+  <name>sparse.img</name>
+  <storage>
+    <allocation>0</allocation>
+    <capacity unit="T">1</capacity>
+  </storage>
+</volume>
diff -r 686cf593fe28 docs/storage/vol-vmdk.xml
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/storage/vol-vmdk.xml	Tue Feb 19 17:22:04 2008 -0500
@@ -0,0 +1,10 @@
+<volume type="file">
+  <name>vmdk3.img</name>
+  <storage>
+    <allocation>0</allocation>
+    <capacity unit="T">1</capacity>
+  </storage>
+  <target>
+    <format type="vmdk"/>
+  </target>
+</volume>
diff -r 686cf593fe28 libvirt.spec.in
--- a/libvirt.spec.in	Tue Feb 19 17:04:59 2008 -0500
+++ b/libvirt.spec.in	Tue Feb 19 17:22:04 2008 -0500
@@ -6,6 +6,12 @@
 %else
 %define with_polkit 0
 %define with_proxy yes
+%endif
+
+%if "%{fedora}"
+%define with_qemu 1
+%else
+%define with_qemu 0
 %endif
 
 Summary: Library providing a simple API virtualization
@@ -34,6 +40,15 @@ Requires: cyrus-sasl-md5
 %if %{with_polkit}
 Requires: PolicyKit >= 0.6
 %endif
+# For mount/umount in FS driver
+BuildRequires: util-linux
+%if %{with_qemu}
+# From QEMU RPMs
+Requires: /usr/bin/qemu-img
+%else
+# From Xen RPMs
+Requires: /usr/sbin/qcow-create
+%endif
 BuildRequires: xen-devel
 BuildRequires: libxml2-devel
 BuildRequires: readline-devel
@@ -48,6 +63,15 @@ BuildRequires: cyrus-sasl-devel
 BuildRequires: cyrus-sasl-devel
 %if %{with_polkit}
 BuildRequires: PolicyKit-devel >= 0.6
+%endif
+# For mount/umount in FS driver
+BuildRequires: util-linux
+%if %{with_qemu}
+# From QEMU RPMs
+BuildRequires: /usr/bin/qemu-img
+%else
+# From Xen RPMs
+BuildRequires: /usr/sbin/qcow-create
 %endif
 Obsoletes: libvir
 ExclusiveArch: i386 x86_64 ia64
diff -r 686cf593fe28 po/POTFILES.in
--- a/po/POTFILES.in	Tue Feb 19 17:04:59 2008 -0500
+++ b/po/POTFILES.in	Tue Feb 19 17:22:04 2008 -0500
@@ -11,6 +11,7 @@ src/qemu_driver.c
 src/qemu_driver.c
 src/remote_internal.c
 src/storage_backend.c
+src/storage_backend_fs.c
 src/storage_conf.c
 src/storage_driver.c
 src/sexpr.c
diff -r 686cf593fe28 src/Makefile.am
--- a/src/Makefile.am	Tue Feb 19 17:04:59 2008 -0500
+++ b/src/Makefile.am	Tue Feb 19 17:22:04 2008 -0500
@@ -62,6 +62,7 @@ CLIENT_SOURCES =						\
 		storage_conf.h storage_conf.c			\
 		storage_driver.h storage_driver.c		\
 		storage_backend.h storage_backend.c		\
+		storage_backend_fs.h storage_backend_fs.c 	\
 		util.c util.h
 
 SERVER_SOURCES = 						\
diff -r 686cf593fe28 src/storage_backend.c
--- a/src/storage_backend.c	Tue Feb 19 17:04:59 2008 -0500
+++ b/src/storage_backend.c	Tue Feb 19 17:22:04 2008 -0500
@@ -40,10 +40,24 @@
 #include "util.h"
 
 #include "storage_backend.h"
+#include "storage_backend_fs.h"
+
+static virStorageBackendPtr backends[] = {
+    &virStorageBackendDirectory,
+#if WITH_STORAGE_FS
+    &virStorageBackendFileSystem,
+    &virStorageBackendNetFileSystem,
+#endif
+};
 
 
 virStorageBackendPtr
 virStorageBackendForType(int type) {
+    unsigned int i;
+    for (i = 0 ; i < (sizeof(backends)/sizeof(backends[0])) ; i++)
+        if (backends[i]->type == type)
+            return backends[i];
+
     virStorageReportError(NULL, VIR_ERR_INTERNAL_ERROR,
                           _("missing backend for pool type %d"), type);
     return NULL;
@@ -68,6 +82,15 @@ virStorageBackendVolOptionsForType(int t
 
 int
 virStorageBackendFromString(const char *type) {
+    if (STREQ(type, "dir"))
+        return VIR_STORAGE_POOL_DIR;
+#if WITH_STORAGE_FS
+    if (STREQ(type, "fs"))
+        return VIR_STORAGE_POOL_FS;
+    if (STREQ(type, "netfs"))
+        return VIR_STORAGE_POOL_NETFS;
+#endif
+
     virStorageReportError(NULL, VIR_ERR_INTERNAL_ERROR,
                           _("unknown storage backend type %s"), type);
     return -1;
@@ -75,6 +98,17 @@ virStorageBackendFromString(const char *
 
 const char *
 virStorageBackendToString(int type) {
+    switch (type) {
+    case VIR_STORAGE_POOL_DIR:
+        return "dir";
+#if WITH_STORAGE_FS
+    case VIR_STORAGE_POOL_FS:
+        return "fs";
+    case VIR_STORAGE_POOL_NETFS:
+        return "netfs";
+#endif
+    }
+
     virStorageReportError(NULL, VIR_ERR_INTERNAL_ERROR,
                           _("unknown storage backend type %d"), type);
     return NULL;
diff -r 686cf593fe28 src/storage_backend_fs.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/storage_backend_fs.c	Tue Feb 19 17:22:05 2008 -0500
@@ -0,0 +1,1123 @@
+/*
+ * storage_backend_fs.c: storage backend for FS and directory handling
+ *
+ * Copyright (C) 2007-2008 Red Hat, Inc.
+ * Copyright (C) 2007-2008 Daniel P. Berrange
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ *
+ * Author: Daniel P. Berrange <berrange at redhat.com>
+ */
+
+#include <config.h>
+
+#include <sys/statvfs.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <endian.h>
+#include <byteswap.h>
+#include <mntent.h>
+#include <string.h>
+
+#include "storage_backend_fs.h"
+#include "storage_conf.h"
+#include "util.h"
+#include "config.h"
+
+
+enum {
+    VIR_STORAGE_POOL_FS_AUTO = 0,
+    VIR_STORAGE_POOL_FS_EXT2,
+    VIR_STORAGE_POOL_FS_EXT3,
+    VIR_STORAGE_POOL_FS_EXT4,
+    VIR_STORAGE_POOL_FS_UFS,
+    VIR_STORAGE_POOL_FS_ISO,
+    VIR_STORAGE_POOL_FS_UDF,
+    VIR_STORAGE_POOL_FS_GFS,
+    VIR_STORAGE_POOL_FS_GFS2,
+    VIR_STORAGE_POOL_FS_VFAT,
+    VIR_STORAGE_POOL_FS_HFSPLUS,
+    VIR_STORAGE_POOL_FS_XFS,
+};
+
+enum {
+    VIR_STORAGE_POOL_NETFS_AUTO = 0,
+    VIR_STORAGE_POOL_NETFS_NFS,
+};
+
+
+
+enum {
+    VIR_STORAGE_VOL_RAW,
+    VIR_STORAGE_VOL_DIR,
+    VIR_STORAGE_VOL_BOCHS,
+    VIR_STORAGE_VOL_CLOOP,
+    VIR_STORAGE_VOL_COW,
+    VIR_STORAGE_VOL_DMG,
+    VIR_STORAGE_VOL_ISO,
+    VIR_STORAGE_VOL_QCOW,
+    VIR_STORAGE_VOL_QCOW2,
+    VIR_STORAGE_VOL_VMDK,
+    VIR_STORAGE_VOL_VPC,
+};
+
+/* Either 'magic' or 'extension' *must* be provided */
+struct {
+    int type;           /* One of the constants above */
+    const char *magic;  /* Optional string of file magic
+                         * to check at head of file */
+    const char *extension; /* Optional file extension to check */
+    int endian;           /* Endianness of file format */
+    int versionOffset;    /* Byte offset from start of file
+                           * where we find version number,
+                           * -1 to skip version test */
+    int versionNumber;    /* Version number to validate */
+    int sizeOffset;       /* Byte offset from start of file
+                           * where we find capacity info,
+                           * -1 to use st_size as capacity */
+    int sizeBytes;        /* Number of bytes for size field */
+    int sizeMultiplier;   /* A scaling factor if size is not in bytes */
+} fileTypeInfo[] = {
+    /* Bochs */
+    /* XXX Untested
+    { VIR_STORAGE_VOL_BOCHS, "Bochs Virtual HD Image", NULL,
+      __LITTLE_ENDIAN, 64, 0x20000,
+      32+16+16+4+4+4+4+4, 8, 1 },*/
+    /* CLoop */
+    /* XXX Untested
+    { VIR_STORAGE_VOL_CLOOP, "#!/bin/sh\n#V2.0 Format\nmodprobe cloop file=$0 && mount -r -t iso9660 /dev/cloop $1\n", NULL,
+      __LITTLE_ENDIAN, -1, 0,
+      -1, 0, 0 }, */
+    /* Cow */
+    { VIR_STORAGE_VOL_COW, "OOOM", NULL,
+      __BIG_ENDIAN, 4, 2,
+      4+4+1024+4, 8, 1 },
+    /* DMG */
+    /* XXX QEMU says there's no magic for dmg, but we should check... */
+    { VIR_STORAGE_VOL_DMG, NULL, ".dmg",
+      0, -1, 0,
+      -1, 0, 0 },
+    /* XXX there's probably some magic for iso we can validate too... */
+    { VIR_STORAGE_VOL_ISO, NULL, ".iso",
+      0, -1, 0,
+      -1, 0, 0 },
+    /* Parallels */
+    /* XXX Untested
+    { VIR_STORAGE_VOL_PARALLELS, "WithoutFreeSpace", NULL,
+      __LITTLE_ENDIAN, 16, 2,
+      16+4+4+4+4, 4, 512 },
+    */
+    /* QCow */
+    { VIR_STORAGE_VOL_QCOW, "QFI", NULL,
+      __BIG_ENDIAN, 4, 1,
+      4+4+8+4+4, 8, 1 },
+    /* QCow 2 */
+    { VIR_STORAGE_VOL_QCOW2, "QFI", NULL,
+      __BIG_ENDIAN, 4, 2,
+      4+4+8+4+4, 8, 1 },
+    /* VMDK 3 */
+    /* XXX Untested
+    { VIR_STORAGE_VOL_VMDK, "COWD", NULL,
+      __LITTLE_ENDIAN, 4, 1,
+      4+4+4, 4, 512 },
+    */
+    /* VMDK 4 */
+    { VIR_STORAGE_VOL_VMDK, "KDMV", NULL,
+      __LITTLE_ENDIAN, 4, 1,
+      4+4+4, 8, 512 },
+    /* Connectix / VirtualPC */
+    /* XXX Untested
+    { VIR_STORAGE_VOL_VPC, "conectix", NULL,
+      __BIG_ENDIAN, -1, 0,
+      -1, 0, 0},
+    */
+};
+
+
+
+
+static int
+virStorageBackendFileSystemVolFormatFromString(virConnectPtr conn,
+                                               const char *format) {
+    if (format == NULL)
+        return VIR_STORAGE_VOL_RAW;
+
+    if (STREQ(format, "raw"))
+        return VIR_STORAGE_VOL_RAW;
+    if (STREQ(format, "dir"))
+        return VIR_STORAGE_VOL_DIR;
+    if (STREQ(format, "bochs"))
+        return VIR_STORAGE_VOL_BOCHS;
+    if (STREQ(format, "cow"))
+        return VIR_STORAGE_VOL_COW;
+    if (STREQ(format, "cloop"))
+        return VIR_STORAGE_VOL_CLOOP;
+    if (STREQ(format, "dmg"))
+        return VIR_STORAGE_VOL_DMG;
+    if (STREQ(format, "iso"))
+        return VIR_STORAGE_VOL_ISO;
+    if (STREQ(format, "qcow"))
+        return VIR_STORAGE_VOL_QCOW;
+    if (STREQ(format, "qcow2"))
+        return VIR_STORAGE_VOL_QCOW2;
+    if (STREQ(format, "vmdk"))
+        return VIR_STORAGE_VOL_VMDK;
+    if (STREQ(format, "vpc"))
+        return VIR_STORAGE_VOL_VPC;
+
+    virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                          _("unsupported volume format %s"), format);
+    return -1;
+}
+
+static const char *
+virStorageBackendFileSystemVolFormatToString(virConnectPtr conn,
+                                             int format) {
+    switch (format) {
+    case VIR_STORAGE_VOL_RAW:
+        return "raw";
+    case VIR_STORAGE_VOL_DIR:
+        return "dir";
+    case VIR_STORAGE_VOL_BOCHS:
+        return "bochs";
+    case VIR_STORAGE_VOL_CLOOP:
+        return "cloop";
+    case VIR_STORAGE_VOL_COW:
+        return "cow";
+    case VIR_STORAGE_VOL_DMG:
+        return "dmg";
+    case VIR_STORAGE_VOL_ISO:
+        return "iso";
+    case VIR_STORAGE_VOL_QCOW:
+        return "qcow";
+    case VIR_STORAGE_VOL_QCOW2:
+        return "qcow2";
+    case VIR_STORAGE_VOL_VMDK:
+        return "vmdk";
+    case VIR_STORAGE_VOL_VPC:
+        return "vpc";
+    }
+
+    virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                          _("unsupported volume format %d"), format);
+    return NULL;
+}
+
+
+static int
+virStorageBackendFileSystemPoolFormatFromString(virConnectPtr conn,
+                                                const char *format) {
+    if (format == NULL)
+        return VIR_STORAGE_POOL_FS_AUTO;
+
+    if (STREQ(format, "auto"))
+        return VIR_STORAGE_POOL_FS_AUTO;
+    if (STREQ(format, "ext2"))
+        return VIR_STORAGE_POOL_FS_EXT2;
+    if (STREQ(format, "ext3"))
+        return VIR_STORAGE_POOL_FS_EXT3;
+    if (STREQ(format, "ext4"))
+        return VIR_STORAGE_POOL_FS_EXT4;
+    if (STREQ(format, "ufs"))
+        return VIR_STORAGE_POOL_FS_UFS;
+    if (STREQ(format, "iso9660"))
+        return VIR_STORAGE_POOL_FS_ISO;
+    if (STREQ(format, "udf"))
+        return VIR_STORAGE_POOL_FS_UDF;
+    if (STREQ(format, "gfs"))
+        return VIR_STORAGE_POOL_FS_GFS;
+    if (STREQ(format, "gfs2"))
+        return VIR_STORAGE_POOL_FS_GFS2;
+    if (STREQ(format, "vfat"))
+        return VIR_STORAGE_POOL_FS_VFAT;
+    if (STREQ(format, "hfs+"))
+        return VIR_STORAGE_POOL_FS_HFSPLUS;
+    if (STREQ(format, "xfs"))
+        return VIR_STORAGE_POOL_FS_XFS;
+
+    virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                          _("unsupported volume format %s"), format);
+    return -1;
+}
+
+static const char *
+virStorageBackendFileSystemPoolFormatToString(virConnectPtr conn,
+                                              int format) {
+    switch (format) {
+    case VIR_STORAGE_POOL_FS_AUTO:
+        return "auto";
+    case VIR_STORAGE_POOL_FS_EXT2:
+        return "ext2";
+    case VIR_STORAGE_POOL_FS_EXT3:
+        return "ext3";
+    case VIR_STORAGE_POOL_FS_EXT4:
+        return "ext4";
+    case VIR_STORAGE_POOL_FS_UFS:
+        return "ufs";
+    case VIR_STORAGE_POOL_FS_ISO:
+        return "iso";
+    case VIR_STORAGE_POOL_FS_UDF:
+        return "udf";
+    case VIR_STORAGE_POOL_FS_GFS:
+        return "gfs";
+    case VIR_STORAGE_POOL_FS_GFS2:
+        return "gfs2";
+    case VIR_STORAGE_POOL_FS_VFAT:
+        return "vfat";
+    case VIR_STORAGE_POOL_FS_HFSPLUS:
+        return "hfs+";
+    case VIR_STORAGE_POOL_FS_XFS:
+        return "xfs";
+    }
+
+    virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                          _("unsupported volume format %d"), format);
+    return NULL;
+}
+
+
+static int
+virStorageBackendFileSystemNetPoolFormatFromString(virConnectPtr conn,
+                                                   const char *format) {
+    if (format == NULL)
+        return VIR_STORAGE_POOL_NETFS_AUTO;
+
+    if (STREQ(format, "auto"))
+        return VIR_STORAGE_POOL_NETFS_AUTO;
+    if (STREQ(format, "nfs"))
+        return VIR_STORAGE_POOL_NETFS_NFS;
+
+    virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                          _("unsupported volume format %s"), format);
+    return -1;
+}
+
+static const char *
+virStorageBackendFileSystemNetPoolFormatToString(virConnectPtr conn,
+                                                 int format) {
+    switch (format) {
+    case VIR_STORAGE_POOL_NETFS_AUTO:
+        return "auto";
+    case VIR_STORAGE_POOL_NETFS_NFS:
+        return "nfs";
+    }
+
+    virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                          _("unsupported volume format %d"), format);
+    return NULL;
+}
+
+
+/**
+ * Probe the header of a file to determine what type of disk image
+ * it is, and info about its capacity if available.
+ */
+static int virStorageBackendProbeFile(virConnectPtr conn,
+                                      virStorageVolDefPtr def) {
+    int fd;
+    char head[4096];
+    int len, i, ret;
+
+    if ((fd = open(def->target.path, O_RDONLY)) < 0) {
+        virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                              _("cannot open volume '%s': %s"),
+                              def->target.path, strerror(errno));
+        return -1;
+    }
+
+    if ((ret = virStorageBackendUpdateVolInfoFD(conn, def, fd, 1)) < 0) {
+        close(fd);
+        return ret; /* Take care to propagate ret, it is not always -1 */
+    }
+
+    if ((len = read(fd, head, sizeof(head))) < 0) {
+        virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                              _("cannot read header '%s': %s"),
+                              def->target.path, strerror(errno));
+        close(fd);
+        return -1;
+    }
+
+    close(fd);
+
+    /* First check file magic */
+    for (i = 0 ; i < sizeof(fileTypeInfo)/sizeof(fileTypeInfo[0]) ; i++) {
+        int mlen;
+        if (fileTypeInfo[i].magic == NULL)
+            continue;
+
+        /* Validate magic data */
+        mlen = strlen(fileTypeInfo[i].magic);
+        if (mlen > len)
+            continue;
+        if (memcmp(head, fileTypeInfo[i].magic, mlen) != 0)
+            continue;
+
+        /* Validate version number info */
+        if (fileTypeInfo[i].versionNumber != -1) {
+            int version;
+
+            if (fileTypeInfo[i].endian == __LITTLE_ENDIAN) {
+                version = (head[fileTypeInfo[i].versionOffset+3] << 24) |
+                    (head[fileTypeInfo[i].versionOffset+2] << 16) |
+                    (head[fileTypeInfo[i].versionOffset+1] << 8) |
+                    head[fileTypeInfo[i].versionOffset];
+            } else {
+                version = (head[fileTypeInfo[i].versionOffset] << 24) |
+                    (head[fileTypeInfo[i].versionOffset+1] << 16) |
+                    (head[fileTypeInfo[i].versionOffset+2] << 8) |
+                    head[fileTypeInfo[i].versionOffset+3];
+            }
+            if (version != fileTypeInfo[i].versionNumber)
+                continue;
+        }
+
+        /* Optionally extract capacity from file */
+        if (fileTypeInfo[i].sizeOffset != -1) {
+            if (fileTypeInfo[i].endian == __LITTLE_ENDIAN) {
+                def->capacity =
+                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset+7] << 56) |
+                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset+6] << 48) |
+                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset+5] << 40) |
+                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset+4] << 32) |
+                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset+3] << 24) |
+                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset+2] << 16) |
+                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset+1] << 8) |
+                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset]);
+            } else {
+                def->capacity =
+                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset] << 56) |
+                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset+1] << 48) |
+                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset+2] << 40) |
+                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset+3] << 32) |
+                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset+4] << 24) |
+                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset+5] << 16) |
+                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset+6] << 8) |
+                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset+7]);
+            }
+            /* Avoid unlikely, but theoretically possible overflow */
+            if (def->capacity > (ULLONG_MAX / fileTypeInfo[i].sizeMultiplier))
+                continue;
+            def->capacity *= fileTypeInfo[i].sizeMultiplier;
+        }
+
+        /* Validation passed, we know the file format now */
+        def->target.format = fileTypeInfo[i].type;
+        return 0;
+    }
+
+    /* No magic, so check file extension */
+    for (i = 0 ; i < sizeof(fileTypeInfo)/sizeof(fileTypeInfo[0]) ; i++) {
+        if (fileTypeInfo[i].extension == NULL)
+            continue;
+
+        if (!virFileHasSuffix(def->target.path, fileTypeInfo[i].extension))
+            continue;
+
+        def->target.format = fileTypeInfo[i].type;
+        return 0;
+    }
+
+    /* All fails, so call it a raw file */
+    def->target.format = VIR_STORAGE_VOL_RAW;
+    return 0;
+}
+
+#if WITH_STORAGE_FS
+/**
+ * @conn connection to report errors against
+ * @pool storage pool to check for status
+ *
+ * Determine if a storage pool is already mounted
+ *
+ * Return 0 if not mounted, 1 if mounted, -1 on error
+ */
+static int
+virStorageBackendFileSystemIsMounted(virConnectPtr conn,
+                                     virStoragePoolObjPtr pool) {
+    FILE *mtab;
+    struct mntent *ent;
+
+    if ((mtab = fopen(_PATH_MOUNTED, "r")) == NULL) {
+        virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                              _("cannot read %s: %s"),
+                              _PATH_MOUNTED, strerror(errno));
+        return -1;
+    }
+
+    while ((ent = getmntent(mtab)) != NULL) {
+        if (STREQ(ent->mnt_dir, pool->def->target.path)) {
+            fclose(mtab);
+            return 1;
+        }
+    }
+
+    fclose(mtab);
+    return 0;
+}
+
+/**
+ * @conn connection to report errors against
+ * @pool storage pool to mount
+ *
+ * Ensure that a FS storage pool is mounted on its target location.
+ * If already mounted, this is a no-op
+ *
+ * Returns 0 if successfully mounted, -1 on error
+ */
+static int
+virStorageBackendFileSystemMount(virConnectPtr conn,
+                                 virStoragePoolObjPtr pool) {
+    char *src;
+    const char *mntargv[] = {
+        MOUNT,
+        "-t",
+        pool->def->type == VIR_STORAGE_POOL_FS ?
+        virStorageBackendFileSystemPoolFormatToString(conn,
+                                                      pool->def->source.format) :
+        virStorageBackendFileSystemNetPoolFormatToString(conn,
+                                                         pool->def->source.format),
+        NULL, /* Fill in shortly - careful not to add extra fields before this */
+        pool->def->target.path,
+        NULL,
+    };
+    int ret;
+
+    if (pool->def->type == VIR_STORAGE_POOL_NETFS) {
+        if (pool->def->source.host.name == NULL) {
+            virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                                  _("missing source host"));
+            return -1;
+        }
+        if (pool->def->source.dir == NULL) {
+            virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                                  _("missing source path"));
+            return -1;
+        }
+    } else {
+        if (pool->def->source.ndevice != 1) {
+            virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                                  _("missing source device"));
+            return -1;
+        }
+    }
+
+    /* Short-circuit is already mounted */
+    if ((ret = virStorageBackendFileSystemIsMounted(conn, pool)) != 0) {
+        if (ret < 0)
+            return -1;
+        else
+            return 0;
+    }
+
+    if (pool->def->type == VIR_STORAGE_POOL_NETFS) {
+        src = malloc(strlen(pool->def->source.host.name) +
+                     1 + strlen(pool->def->source.dir) + 1);
+        strcpy(src, pool->def->source.host.name);
+        strcat(src, ":");
+        strcat(src, pool->def->source.dir);
+    } else {
+        src = strdup(pool->def->source.devices[0].path);
+    }
+    if (src == NULL) {
+        virStorageReportError(conn, VIR_ERR_NO_MEMORY, _("source"));
+        return -1;
+    }
+    mntargv[3] = src;
+
+    if (virRun(conn, (char**)mntargv, NULL) < 0) {
+        free(src);
+        return -1;
+    }
+    free(src);
+    return 0;
+}
+
+/**
+ * @conn connection to report errors against
+ * @pool storage pool to unmount
+ *
+ * Ensure that a FS storage pool is not mounted on its target location.
+ * If already unmounted, this is a no-op
+ *
+ * Returns 0 if successfully unmounted, -1 on error
+ */
+static int
+virStorageBackendFileSystemUnmount(virConnectPtr conn,
+                                   virStoragePoolObjPtr pool) {
+    const char *mntargv[3];
+    int ret;
+
+    if (pool->def->type == VIR_STORAGE_POOL_NETFS) {
+        if (pool->def->source.host.name == NULL) {
+            virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                                  _("missing source host"));
+            return -1;
+        }
+        if (pool->def->source.dir == NULL) {
+            virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                                  _("missing source dir"));
+            return -1;
+        }
+    } else {
+        if (pool->def->source.ndevice != 1) {
+            virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                                  _("missing source device"));
+            return -1;
+        }
+    }
+
+    /* Short-circuit if already unmounted */
+    if ((ret = virStorageBackendFileSystemIsMounted(conn, pool)) != 1) {
+        if (ret < 0)
+            return -1;
+        else
+            return 0;
+    }
+
+    mntargv[0] = UMOUNT;
+    mntargv[1] = pool->def->target.path;
+    mntargv[2] = NULL;
+
+    if (virRun(conn, (char**)mntargv, NULL) < 0) {
+        return -1;
+    }
+    return 0;
+}
+#endif /* WITH_STORAGE_FS */
+
+
+/**
+ * @conn connection to report errors against
+ * @pool storage pool to start
+ *
+ * Starts a directory or FS based storage pool.
+ *
+ *  - If it is a FS based pool, mounts the unlying source device on the pool
+ *
+ * Returns 0 on success, -1 on error
+ */
+#if WITH_STORAGE_FS
+static int
+virStorageBackendFileSystemStart(virConnectPtr conn,
+                                 virStoragePoolObjPtr pool)
+{
+    if (pool->def->type != VIR_STORAGE_POOL_DIR &&
+        virStorageBackendFileSystemMount(conn, pool) < 0)
+        return -1;
+
+    return 0;
+}
+#endif /* WITH_STORAGE_FS */
+
+
+/**
+ * @conn connection to report errors against
+ * @pool storage pool to build
+ *
+ * Build a directory or FS based storage pool.
+ *
+ *  - If it is a FS based pool, mounts the unlying source device on the pool
+ *
+ * Returns 0 on success, -1 on error
+ */
+static int
+virStorageBackendFileSystemBuild(virConnectPtr conn,
+                                 virStoragePoolObjPtr pool,
+                                 unsigned int flags ATTRIBUTE_UNUSED)
+{
+    if (virFileMakePath(pool->def->target.path) < 0) {
+        virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                              _("cannot create path '%s': %s"),
+                              pool->def->target.path, strerror(errno));
+        return -1;
+    }
+
+    return 0;
+}
+
+
+/**
+ * Iterate over the pool's directory and enumerate all disk images
+ * within it. This is non-recursive.
+ */
+static int
+virStorageBackendFileSystemRefresh(virConnectPtr conn,
+                                   virStoragePoolObjPtr pool)
+{
+    DIR *dir;
+    struct dirent *ent;
+    struct statvfs sb;
+
+    if (!(dir = opendir(pool->def->target.path))) {
+        virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                              _("cannot open path '%s': %s"),
+                              pool->def->target.path, strerror(errno));
+        goto cleanup;
+    }
+
+    while ((ent = readdir(dir)) != NULL) {
+        virStorageVolDefPtr vol;
+        int ret;
+
+        vol = calloc(1, sizeof(virStorageVolDef));
+        if (vol == NULL) {
+            virStorageReportError(conn, VIR_ERR_NO_MEMORY,
+                                  _("volume"));
+            goto cleanup;
+        }
+
+        vol->name = strdup(ent->d_name);
+        if (vol->name == NULL) {
+            free(vol);
+            virStorageReportError(conn, VIR_ERR_NO_MEMORY,
+                                  _("volume name"));
+            goto cleanup;
+        }
+
+        vol->target.format = VIR_STORAGE_VOL_RAW; /* Real value is filled in during probe */
+        vol->target.path = malloc(strlen(pool->def->target.path) +
+                                  1 + strlen(vol->name) + 1);
+        if (vol->target.path == NULL) {
+            free(vol->target.path);
+            free(vol);
+            virStorageReportError(conn, VIR_ERR_NO_MEMORY,
+                                  _("volume name"));
+            goto cleanup;
+        }
+        strcpy(vol->target.path, pool->def->target.path);
+        strcat(vol->target.path, "/");
+        strcat(vol->target.path, vol->name);
+        if ((vol->key = strdup(vol->target.path)) == NULL) {
+            free(vol->name);
+            free(vol->target.path);
+            free(vol);
+            virStorageReportError(conn, VIR_ERR_NO_MEMORY,
+                                  _("volume key"));
+            goto cleanup;
+        }
+
+        if ((ret = virStorageBackendProbeFile(conn, vol) < 0)) {
+            free(vol->key);
+            free(vol->name);
+            free(vol->target.path);
+            free(vol);
+            if (ret == -1)
+                goto cleanup;
+            else
+                /* Silently ignore non-regular files,
+                 * eg '.' '..', 'lost+found' */
+                continue;
+        }
+
+        vol->next = pool->volumes;
+        pool->volumes = vol;
+        pool->nvolumes++;
+        continue;
+    }
+    closedir(dir);
+
+
+    if (statvfs(pool->def->target.path, &sb) < 0) {
+        virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                              _("cannot statvfs path '%s': %s"),
+                              pool->def->target.path, strerror(errno));
+        return -1;
+    }
+    pool->def->capacity = ((unsigned long long)sb.f_frsize *
+                           (unsigned long long)sb.f_blocks);
+    pool->def->available = ((unsigned long long)sb.f_bfree *
+                            (unsigned long long)sb.f_bsize);
+    pool->def->allocation = pool->def->capacity - pool->def->available;
+
+    return 0;
+
+ cleanup:
+    closedir(dir);
+    virStoragePoolObjClearVols(pool);
+    return -1;
+}
+
+
+/**
+ * @conn connection to report errors against
+ * @pool storage pool to start
+ *
+ * Stops a directory or FS based storage pool.
+ *
+ *  - If it is a FS based pool, unmounts the unlying source device on the pool
+ *  - Releases all cached data about volumes
+ */
+#if WITH_STORAGE_FS
+static int
+virStorageBackendFileSystemStop(virConnectPtr conn,
+                                virStoragePoolObjPtr pool)
+{
+    if (pool->def->type != VIR_STORAGE_POOL_DIR &&
+        virStorageBackendFileSystemUnmount(conn, pool) < 0)
+        return -1;
+
+    return 0;
+}
+#endif /* WITH_STORAGE_FS */
+
+
+/**
+ * @conn connection to report errors against
+ * @pool storage pool to build
+ *
+ * Build a directory or FS based storage pool.
+ *
+ *  - If it is a FS based pool, mounts the unlying source device on the pool
+ *
+ * Returns 0 on success, -1 on error
+ */
+static int
+virStorageBackendFileSystemDelete(virConnectPtr conn,
+                                  virStoragePoolObjPtr pool,
+                                  unsigned int flags ATTRIBUTE_UNUSED)
+{
+    /* XXX delete all vols first ? */
+
+    if (unlink(pool->def->target.path) < 0) {
+        virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                              _("cannot unlink path '%s': %s"),
+                              pool->def->target.path, strerror(errno));
+        return -1;
+    }
+
+    return 0;
+}
+
+
+/**
+ * Allocate a new file as a volume. This is either done directly
+ * for raw/sparse files, or by calling qemu-img/qcow-create for
+ * special kinds of files
+ */
+static int
+virStorageBackendFileSystemVolCreate(virConnectPtr conn,
+                                     virStoragePoolObjPtr pool,
+                                     virStorageVolDefPtr vol)
+{
+    int fd;
+
+    vol->target.path = malloc(strlen(pool->def->target.path) +
+                              1 + strlen(vol->name) + 1);
+    if (vol->target.path == NULL) {
+        virStorageReportError(conn, VIR_ERR_NO_MEMORY, _("target"));
+        return -1;
+    }
+    strcpy(vol->target.path, pool->def->target.path);
+    strcat(vol->target.path, "/");
+    strcat(vol->target.path, vol->name);
+    vol->key = strdup(vol->target.path);
+    if (vol->key == NULL) {
+        virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                              _("storage vol key"));
+        return -1;
+    }
+
+    if (vol->target.format == VIR_STORAGE_VOL_RAW) {
+        if ((fd = open(vol->target.path, O_RDWR | O_CREAT | O_EXCL,
+                       vol->target.perms.mode)) < 0) {
+            virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                                  _("cannot create path '%s': %s"),
+                                  vol->target.path, strerror(errno));
+            return -1;
+        }
+
+        /* Pre-allocate any data if requested */
+        /* XXX slooooooooooooooooow.
+         * Need to add in progress bars & bg thread somehow */
+        if (vol->allocation) {
+            unsigned long long remain = vol->allocation;
+            static const char const zeros[4096];
+            while (remain) {
+                int bytes = sizeof(zeros);
+                if (bytes > remain)
+                    bytes = remain;
+                if ((bytes = write(fd, zeros, bytes)) < 0) {
+                    virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                                          _("cannot fill file '%s': %s"),
+                                          vol->target.path, strerror(errno));
+                    unlink(vol->target.path);
+                    close(fd);
+                    return -1;
+                }
+                remain -= bytes;
+            }
+        }
+
+        /* Now seek to final size, possibly making the file sparse */
+        if (ftruncate(fd, vol->capacity) < 0) {
+            virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                                  _("cannot extend file '%s': %s"),
+                                  vol->target.path, strerror(errno));
+            unlink(vol->target.path);
+            close(fd);
+            return -1;
+        }
+    } else if (vol->target.format == VIR_STORAGE_VOL_DIR) {
+        if (mkdir(vol->target.path, vol->target.perms.mode) < 0) {
+            virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                                  _("cannot create path '%s': %s"),
+                                  vol->target.path, strerror(errno));
+            return -1;
+        }
+
+        if ((fd = open(vol->target.path, O_RDWR)) < 0) {
+            virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                                  _("cannot read path '%s': %s"),
+                                  vol->target.path, strerror(errno));
+            return -1;
+        }
+    } else {
+#if HAVE_QEMU_IMG
+        const char *type;
+        char size[100];
+        const char *imgargv[7];
+
+        if ((type = virStorageBackendFileSystemVolFormatToString(conn,
+                                                                 vol->target.format)) == NULL) {
+            virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                                  _("unknown storage vol type %d"),
+                                  vol->target.format);
+            return -1;
+        }
+
+        /* Size in KB */
+        snprintf(size, sizeof(size), "%llu", vol->capacity/1024);
+
+        imgargv[0] = QEMU_IMG;
+        imgargv[1] = "create";
+        imgargv[2] = "-f";
+        imgargv[3] = type;
+        imgargv[4] = vol->target.path;
+        imgargv[5] = size;
+        imgargv[6] = NULL;
+
+        if (virRun(conn, (char **)imgargv, NULL) < 0) {
+            unlink(vol->target.path);
+            return -1;
+        }
+
+        if ((fd = open(vol->target.path, O_RDONLY)) < 0) {
+            virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                                  _("cannot read path '%s': %s"),
+                                  vol->target.path, strerror(errno));
+            unlink(vol->target.path);
+            return -1;
+        }
+#elif HAVE_QCOW_CREATE
+        /*
+         * Xen removed the fully-functional qemu-img, and replaced it
+         * with a partially functional qcow-create. Go figure ??!?
+         */
+        char size[100];
+        const char *imgargv[4];
+
+        if (vol->target.format != VIR_STORAGE_VOL_QCOW2) {
+            virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                                  _("unsupported storage vol type %d"),
+                                  vol->target.format);
+            return -1;
+        }
+
+        /* Size in MB - yes different units to qemu-img :-( */
+        snprintf(size, sizeof(size), "%llu", vol->capacity/1024/1024);
+
+        imgargv[0] = QCOW_CREATE;
+        imgargv[1] = size;
+        imgargv[2] = vol->target.path;
+        imgargv[3] = NULL;
+
+        if (virRun(conn, (char **)imgargv, NULL) < 0) {
+            unlink(vol->target.path);
+            return -1;
+        }
+
+        if ((fd = open(vol->target.path, O_RDONLY)) < 0) {
+            virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                                  _("cannot read path '%s': %s"),
+                                  vol->target.path, strerror(errno));
+            unlink(vol->target.path);
+            return -1;
+        }
+#else
+        virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                              _("creation of non-raw images is not supported without qemu-img"));
+        return -1;
+#endif
+    }
+
+    /* We can only chown/grp if root */
+    if (getuid() == 0) {
+        if (fchown(fd, vol->target.perms.uid, vol->target.perms.gid) < 0) {
+            virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                                  _("cannot set file owner '%s': %s"),
+                                  vol->target.path, strerror(errno));
+            unlink(vol->target.path);
+            close(fd);
+            return -1;
+        }
+    }
+    if (fchmod(fd, vol->target.perms.mode) < 0) {
+        virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                              _("cannot set file mode '%s': %s"),
+                              vol->target.path, strerror(errno));
+        unlink(vol->target.path);
+        close(fd);
+        return -1;
+    }
+
+    /* Refresh allocation / permissions info, but not capacity */
+    if (virStorageBackendUpdateVolInfoFD(conn, vol, fd, 0) < 0) {
+        unlink(vol->target.path);
+        close(fd);
+        return -1;
+    }
+
+    if (close(fd) < 0) {
+        virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                              _("cannot close file '%s': %s"),
+                              vol->target.path, strerror(errno));
+        unlink(vol->target.path);
+        return -1;
+    }
+
+    return 0;
+}
+
+
+/**
+ * Remove a volume - just unlinks for now
+ */
+static int
+virStorageBackendFileSystemVolDelete(virConnectPtr conn,
+                                     virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
+                                     virStorageVolDefPtr vol,
+                                     unsigned int flags ATTRIBUTE_UNUSED)
+{
+    if (unlink(vol->target.path) < 0) {
+        /* Silently ignore failures where the vol has already gone away */
+        if (errno != ENOENT) {
+            virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                                  _("cannot unlink file '%s': %s"),
+                                  vol->target.path, strerror(errno));
+            return -1;
+        }
+    }
+    return 0;
+}
+
+
+/**
+ * Update info about a volume's capacity/allocation
+ */
+static int
+virStorageBackendFileSystemVolRefresh(virConnectPtr conn,
+                                      virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
+                                      virStorageVolDefPtr vol)
+{
+    /* Refresh allocation / permissions info in case its changed */
+    return virStorageBackendUpdateVolInfo(conn, vol, 0);
+}
+
+virStorageBackend virStorageBackendDirectory = {
+    .type = VIR_STORAGE_POOL_DIR,
+
+    .buildPool = virStorageBackendFileSystemBuild,
+    .refreshPool = virStorageBackendFileSystemRefresh,
+    .deletePool = virStorageBackendFileSystemDelete,
+    .createVol = virStorageBackendFileSystemVolCreate,
+    .refreshVol = virStorageBackendFileSystemVolRefresh,
+    .deleteVol = virStorageBackendFileSystemVolDelete,
+
+    .volOptions = {
+        .formatFromString = virStorageBackendFileSystemVolFormatFromString,
+        .formatToString = virStorageBackendFileSystemVolFormatToString,
+    },
+    .volType = VIR_STORAGE_VOL_FILE,
+};
+
+#if WITH_STORAGE_FS
+virStorageBackend virStorageBackendFileSystem = {
+    .type = VIR_STORAGE_POOL_FS,
+
+    .buildPool = virStorageBackendFileSystemBuild,
+    .startPool = virStorageBackendFileSystemStart,
+    .refreshPool = virStorageBackendFileSystemRefresh,
+    .stopPool = virStorageBackendFileSystemStop,
+    .deletePool = virStorageBackendFileSystemDelete,
+    .createVol = virStorageBackendFileSystemVolCreate,
+    .refreshVol = virStorageBackendFileSystemVolRefresh,
+    .deleteVol = virStorageBackendFileSystemVolDelete,
+
+    .poolOptions = {
+        .flags = (VIR_STORAGE_BACKEND_POOL_SOURCE_DEVICE),
+        .formatFromString = virStorageBackendFileSystemPoolFormatFromString,
+        .formatToString = virStorageBackendFileSystemPoolFormatToString,
+    },
+    .volOptions = {
+        .formatFromString = virStorageBackendFileSystemVolFormatFromString,
+        .formatToString = virStorageBackendFileSystemVolFormatToString,
+    },
+    .volType = VIR_STORAGE_VOL_FILE,
+};
+virStorageBackend virStorageBackendNetFileSystem = {
+    .type = VIR_STORAGE_POOL_NETFS,
+
+    .buildPool = virStorageBackendFileSystemBuild,
+    .startPool = virStorageBackendFileSystemStart,
+    .refreshPool = virStorageBackendFileSystemRefresh,
+    .stopPool = virStorageBackendFileSystemStop,
+    .deletePool = virStorageBackendFileSystemDelete,
+    .createVol = virStorageBackendFileSystemVolCreate,
+    .refreshVol = virStorageBackendFileSystemVolRefresh,
+    .deleteVol = virStorageBackendFileSystemVolDelete,
+
+    .poolOptions = {
+        .flags = (VIR_STORAGE_BACKEND_POOL_SOURCE_HOST |
+                  VIR_STORAGE_BACKEND_POOL_SOURCE_DIR),
+        .formatFromString = virStorageBackendFileSystemNetPoolFormatFromString,
+        .formatToString = virStorageBackendFileSystemNetPoolFormatToString,
+    },
+    .volOptions = {
+        .formatFromString = virStorageBackendFileSystemVolFormatFromString,
+        .formatToString = virStorageBackendFileSystemVolFormatToString,
+    },
+    .volType = VIR_STORAGE_VOL_FILE,
+};
+#endif /* WITH_STORAGE_FS */
+
+/*
+ * vim: set tabstop=4:
+ * vim: set shiftwidth=4:
+ * vim: set expandtab:
+ */
+/*
+ * Local variables:
+ *  indent-tabs-mode: nil
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 4
+ * End:
+ */
diff -r 686cf593fe28 src/storage_backend_fs.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/storage_backend_fs.h	Tue Feb 19 17:22:05 2008 -0500
@@ -0,0 +1,49 @@
+/*
+ * storage_backend_fs.h: storage backend for FS and directory handling
+ *
+ * Copyright (C) 2007-2008 Red Hat, Inc.
+ * Copyright (C) 2007-2008 Daniel P. Berrange
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ *
+ * Author: Daniel P. Berrange <berrange at redhat.com>
+ */
+
+#ifndef __VIR_STORAGE_BACKEND_FS_H__
+#define __VIR_STORAGE_BACKEND_FS_H__
+
+#include "storage_backend.h"
+
+#if WITH_STORAGE_FS
+extern virStorageBackend virStorageBackendFileSystem;
+extern virStorageBackend virStorageBackendNetFileSystem;
+#endif
+extern virStorageBackend virStorageBackendDirectory;
+
+#endif /* __VIR_STORAGE_BACKEND_FS_H__ */
+
+/*
+ * vim: set tabstop=4:
+ * vim: set shiftwidth=4:
+ * vim: set expandtab:
+ */
+/*
+ * Local variables:
+ *  indent-tabs-mode: nil
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 4
+ * End:
+ */


-- 
|=- Red Hat, Engineering, Emerging Technologies, Boston.  +1 978 392 2496 -=|
|=-           Perl modules: http://search.cpan.org/~danberr/              -=|
|=-               Projects: http://freshmeat.net/~danielpb/               -=|
|=-  GnuPG: 7D3B9505   F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505  -=| 




More information about the libvir-list mailing list