summaryrefslogtreecommitdiffstats
path: root/daemon/upload.c
diff options
context:
space:
mode:
authorRichard Jones <rjones@redhat.com>2009-04-20 00:22:02 +0100
committerRichard Jones <rjones@redhat.com>2009-04-20 00:22:02 +0100
commit170f262f0413de843af62b968f6d12c1c476ae7f (patch)
treeb9be7ae0e59f784dfdd57ef063536218ee3f0c7d /daemon/upload.c
parentd5151686d82b66c50935010fd5458be0e4386bab (diff)
downloadlibguestfs-170f262f0413de843af62b968f6d12c1c476ae7f.tar.gz
libguestfs-170f262f0413de843af62b968f6d12c1c476ae7f.tar.xz
libguestfs-170f262f0413de843af62b968f6d12c1c476ae7f.zip
Implement upload and download commands.
Diffstat (limited to 'daemon/upload.c')
-rw-r--r--daemon/upload.c95
1 files changed, 91 insertions, 4 deletions
diff --git a/daemon/upload.c b/daemon/upload.c
index d2feb028..b4576950 100644
--- a/daemon/upload.c
+++ b/daemon/upload.c
@@ -27,14 +27,101 @@
#include "daemon.h"
#include "actions.h"
+static int
+write_cb (void *fd_ptr, const void *buf, int len)
+{
+ int fd = *(int *)fd_ptr;
+ return xwrite (fd, buf, len);
+}
+
+/* Has one FileIn parameter. */
int
-do_upload (const char *remote_filename)
+do_upload (const char *filename)
{
- XXX_NOT_IMPL (-1);
+ int err, fd, r, is_dev;
+
+ NEED_ROOT_OR_IS_DEVICE (filename, -1);
+
+ is_dev = strncmp (filename, "/dev/", 5) == 0;
+
+ if (!is_dev) CHROOT_IN;
+ fd = open (filename, O_WRONLY|O_CREAT|O_TRUNC|O_NOCTTY, 0666);
+ if (!is_dev) CHROOT_OUT;
+ if (fd == -1) {
+ err = errno;
+ cancel_receive ();
+ errno = err;
+ reply_with_perror ("%s", filename);
+ return -1;
+ }
+
+ r = receive_file (write_cb, &fd);
+ if (r == -1) { /* write error */
+ err = errno;
+ cancel_receive ();
+ errno = err;
+ reply_with_perror ("write: %s", filename);
+ return -1;
+ }
+ if (r == -2) { /* cancellation from library */
+ close (fd);
+ /* Do NOT send any error. */
+ return -1;
+ }
+
+ if (close (fd) == -1) {
+ err = errno;
+ cancel_receive ();
+ errno = err;
+ reply_with_perror ("close: %s", filename);
+ return -1;
+ }
+
+ return 0;
}
+/* Has one FileOut parameter. */
int
-do_download (const char *remote_filename)
+do_download (const char *filename)
{
- XXX_NOT_IMPL (-1);
+ int fd, r, is_dev;
+ char buf[GUESTFS_MAX_CHUNK_SIZE];
+
+ NEED_ROOT_OR_IS_DEVICE (filename, -1);
+
+ is_dev = strncmp (filename, "/dev/", 5) == 0;
+
+ if (!is_dev) CHROOT_IN;
+ fd = open (filename, O_RDONLY);
+ if (!is_dev) CHROOT_OUT;
+ if (fd == -1) {
+ reply_with_perror ("%s", filename);
+ return -1;
+ }
+
+ /* Now we must send the reply message, before the file contents. After
+ * this there is no opportunity in the protocol to send any error
+ * message back. Instead we can only cancel the transfer.
+ */
+ reply (NULL, NULL);
+
+ while ((r = read (fd, buf, sizeof buf)) > 0) {
+ if (send_file_write (buf, r) < 0)
+ return -1;
+ }
+
+ if (r == -1) {
+ perror (filename);
+ send_file_end (1); /* Cancel. */
+ return -1;
+ }
+
+ if (close (fd) == -1) {
+ perror (filename);
+ send_file_end (1); /* Cancel. */
+ return -1;
+ }
+
+ send_file_end (0); /* Normal end of file. */
+ return 0;
}