build: Add ./configure --disable-fuse option.
[libguestfs.git] / daemon / dd.c
index 0a53b31..f08eb36 100644 (file)
@@ -21,8 +21,9 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <fcntl.h>
 
-#include "../src/guestfs_protocol.h"
+#include "guestfs_protocol.h"
 #include "daemon.h"
 #include "actions.h"
 
@@ -62,7 +63,7 @@ do_dd (const char *src, const char *dest)
   free (of_arg);
 
   if (r == -1) {
-    reply_with_error ("dd: %s: %s: %s", src, dest, err);
+    reply_with_error ("%s: %s: %s", src, dest, err);
     free (err);
     return -1;
   }
@@ -70,3 +71,94 @@ do_dd (const char *src, const char *dest)
 
   return 0;
 }
+
+int
+do_copy_size (const char *src, const char *dest, int64_t ssize)
+{
+  char *buf;
+  int src_fd, dest_fd;
+
+  if (STRPREFIX (src, "/dev/"))
+    src_fd = open (src, O_RDONLY);
+  else {
+    buf = sysroot_path (src);
+    if (!buf) {
+      reply_with_perror ("malloc");
+      return -1;
+    }
+    src_fd = open (buf, O_RDONLY);
+    free (buf);
+  }
+  if (src_fd == -1) {
+    reply_with_perror ("%s", src);
+    return -1;
+  }
+
+  if (STRPREFIX (dest, "/dev/"))
+    dest_fd = open (dest, O_WRONLY);
+  else {
+    buf = sysroot_path (dest);
+    if (!buf) {
+      reply_with_perror ("malloc");
+      close (src_fd);
+      return -1;
+    }
+    dest_fd = open (buf, O_WRONLY|O_CREAT|O_TRUNC|O_NOCTTY, 0666);
+    free (buf);
+  }
+  if (dest_fd == -1) {
+    reply_with_perror ("%s", dest);
+    close (src_fd);
+    return -1;
+  }
+
+  uint64_t position = 0, size = (uint64_t) ssize;
+
+  while (position < size) {
+    char buf[1024*1024];
+
+    /* Calculate bytes to copy. */
+    uint64_t n64 = size - position;
+    size_t n;
+    if (n64 > sizeof buf)
+      n = sizeof buf;
+    else
+      n = (size_t) n64; /* safe because of if condition */
+
+    ssize_t r = read (src_fd, buf, n);
+    if (r == -1) {
+      reply_with_perror ("%s: read", src);
+      close (src_fd);
+      close (dest_fd);
+      return -1;
+    }
+    if (r == 0) {
+      reply_with_error ("%s: input file too short", src);
+      close (src_fd);
+      close (dest_fd);
+      return -1;
+    }
+
+    if (xwrite (dest_fd, buf, r) == -1) {
+      reply_with_perror ("%s: write", dest);
+      close (src_fd);
+      close (dest_fd);
+      return -1;
+    }
+
+    position += r;
+    notify_progress ((uint64_t) position, (uint64_t) size);
+  }
+
+  if (close (src_fd) == -1) {
+    reply_with_perror ("%s: close", src);
+    close (dest_fd);
+    return -1;
+  }
+  if (close (dest_fd) == -1) {
+    reply_with_perror ("%s: close", dest);
+    return -1;
+  }
+
+  return 0;
+}