New APIs: base64-in and base64-out for uploading/downloading base64 content.
authorRichard Jones <rjones@redhat.com>
Mon, 19 Apr 2010 16:09:58 +0000 (17:09 +0100)
committerRichard Jones <rjones@redhat.com>
Mon, 19 Apr 2010 16:09:58 +0000 (17:09 +0100)
.gitignore
TODO
daemon/Makefile.am
daemon/base64.c [new file with mode: 0644]
images/Makefile.am
po/POTFILES.in
src/MAX_PROC_NR
src/generator.ml

index fa23150..382cbcf 100644 (file)
@@ -103,6 +103,7 @@ images/100kallspaces
 images/100kallzeroes
 images/100krandom
 images/10klines
+images/hello.b64
 images/initrd
 images/initrd-x86_64.img
 images/initrd-x86_64.img.gz
diff --git a/TODO b/TODO
index e99f7ed..56b429a 100644 (file)
--- a/TODO
+++ b/TODO
@@ -271,26 +271,3 @@ List filesystems by UUID or label.
 Mount filesystems by UUID or label.  (I'm not really sure if we can do
 this at the moment but we ought to be able to do it, and perhaps make
 it easier by having a direct command).
-
-UUencoded uploads
------------------
-
-(Or base64).  Something like:
-
-base64-in -<<EOF
-TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlz
-IHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2Yg
-dGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGlu
-dWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRo
-ZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4=
-EOF
-
-Arbitrary scripts
------------------
-
-debug-upload -<<EOF script
-#!/bin/sh -
-...
-EOF
-
-debug sh ...
index 7bfb280..3fa2b31 100644 (file)
@@ -64,6 +64,7 @@ guestfsd_SOURCES = \
        actions.h \
        available.c \
        augeas.c \
+       base64.c \
        blkid.c \
        blockdev.c \
        checksum.c \
diff --git a/daemon/base64.c b/daemon/base64.c
new file mode 100644 (file)
index 0000000..89bf437
--- /dev/null
@@ -0,0 +1,150 @@
+/* libguestfs - the guestfsd daemon
+ * Copyright (C) 2010 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+
+#include "../src/guestfs_protocol.h"
+#include "daemon.h"
+#include "actions.h"
+
+static int
+write_cb (void *fd_ptr, const void *buf, size_t len)
+{
+  int fd = *(int *)fd_ptr;
+  return xwrite (fd, buf, len);
+}
+
+/* Has one FileIn parameter. */
+int
+do_base64_in (const char *file)
+{
+  int err, r;
+  FILE *fp;
+  char *cmd;
+
+  if (asprintf_nowarn (&cmd, "base64 -d > %R", file) == -1) {
+    err = errno;
+    cancel_receive ();
+    errno = err;
+    reply_with_perror ("asprintf");
+    return -1;
+  }
+
+  if (verbose)
+    fprintf (stderr, "%s\n", cmd);
+
+  fp = popen (cmd, "w");
+  if (fp == NULL) {
+    err = errno;
+    cancel_receive ();
+    errno = err;
+    reply_with_perror ("%s", cmd);
+    free (cmd);
+    return -1;
+  }
+  free (cmd);
+
+  /* The semantics of fwrite are too undefined, so write to the
+   * file descriptor directly instead.
+   */
+  int fd = fileno (fp);
+
+  r = receive_file (write_cb, &fd);
+  if (r == -1) {               /* write error */
+    cancel_receive ();
+    reply_with_error ("write error on file: %s", file);
+    pclose (fp);
+    return -1;
+  }
+  if (r == -2) {               /* cancellation from library */
+    pclose (fp);
+    /* Do NOT send any error. */
+    return -1;
+  }
+
+  if (pclose (fp) != 0) {
+    if (r == -1)                /* if r == 0, file transfer ended already */
+      cancel_receive ();
+    reply_with_error ("base64 subcommand failed on file: %s", file);
+    return -1;
+  }
+
+  return 0;
+}
+
+/* Has one FileOut parameter. */
+int
+do_base64_out (const char *file)
+{
+  int r;
+  FILE *fp;
+  char *cmd;
+  char buf[GUESTFS_MAX_CHUNK_SIZE];
+
+  if (asprintf_nowarn (&cmd, "base64 %R", file) == -1) {
+    reply_with_perror ("asprintf");
+    return -1;
+  }
+
+  if (verbose)
+    fprintf (stderr, "%s\n", cmd);
+
+  fp = popen (cmd, "r");
+  if (fp == NULL) {
+    reply_with_perror ("%s", cmd);
+    free (cmd);
+    return -1;
+  }
+  free (cmd);
+
+  /* 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 = fread (buf, 1, sizeof buf, fp)) > 0) {
+    if (send_file_write (buf, r) < 0) {
+      pclose (fp);
+      return -1;
+    }
+  }
+
+  if (ferror (fp)) {
+    perror (file);
+    send_file_end (1);         /* Cancel. */
+    pclose (fp);
+    return -1;
+  }
+
+  if (pclose (fp) != 0) {
+    perror (file);
+    send_file_end (1);         /* Cancel. */
+    return -1;
+  }
+
+  if (send_file_end (0))       /* Normal end of file. */
+    return -1;
+
+  return 0;
+}
index ff8d46f..7f35b75 100644 (file)
@@ -73,6 +73,7 @@ images_files_build = \
        $(builddir)/100kallspaces \
        $(builddir)/100krandom \
        $(builddir)/10klines \
+       $(builddir)/hello.b64 \
        $(builddir)/initrd \
        $(builddir)/initrd-x86_64.img \
        $(builddir)/initrd-x86_64.img.gz \
@@ -118,6 +119,9 @@ $(builddir)/10klines:
        done > $@-t
        mv $@-t $@
 
+$(builddir)/hello.b64:
+       echo "hello" | base64 > $@
+
 $(builddir)/initrd: empty known-1 known-2 known-3 known-4 known-5
        rm -f $@ $@-t
        for f in $^; do echo $$f; done | cpio -o -H newc | gzip --best > $@-t
index a5a27fa..aebe450 100644 (file)
@@ -1,6 +1,7 @@
 appliance/libguestfs-supermin-helper.c
 daemon/augeas.c
 daemon/available.c
+daemon/base64.c
 daemon/blkid.c
 daemon/blockdev.c
 daemon/checksum.c
index f06fa6c..77f8323 100644 (file)
@@ -1 +1 @@
-241
+243
index 77fa053..b274411 100755 (executable)
@@ -4520,6 +4520,22 @@ There is no comprehensive help for this command.  You have
 to look at the file C<daemon/debug.c> in the libguestfs source
 to find out what it is for.");
 
+  ("base64_in", (RErr, [FileIn "base64file"; Pathname "filename"]), 242, [],
+   [InitBasicFS, Always, TestOutput (
+      [["base64_in"; "../images/hello.b64"; "/hello"];
+       ["cat"; "/hello"]], "hello\n")],
+   "upload base64-encoded data to file",
+   "\
+This command uploads base64-encoded data from C<base64file>
+to C<filename>.");
+
+  ("base64_out", (RErr, [Pathname "filename"; FileOut "base64file"]), 243, [],
+   [],
+   "download file and encode as base64",
+   "\
+This command downloads the contents of C<filename>, writing
+it out to local file C<base64file> encoded as base64.");
+
 ]
 
 let all_functions = non_daemon_functions @ daemon_functions