From c3a68961859a617f7c574c528d0f8ac1fdbb53e1 Mon Sep 17 00:00:00 2001 From: Richard Jones Date: Mon, 19 Apr 2010 17:09:58 +0100 Subject: [PATCH] New APIs: base64-in and base64-out for uploading/downloading base64 content. --- .gitignore | 1 + TODO | 23 -------- daemon/Makefile.am | 1 + daemon/base64.c | 150 +++++++++++++++++++++++++++++++++++++++++++++++++++++ images/Makefile.am | 4 ++ po/POTFILES.in | 1 + src/MAX_PROC_NR | 2 +- src/generator.ml | 16 ++++++ 8 files changed, 174 insertions(+), 24 deletions(-) create mode 100644 daemon/base64.c diff --git a/.gitignore b/.gitignore index fa23150..382cbcf 100644 --- a/.gitignore +++ b/.gitignore @@ -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 --- 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 -< + +#include +#include +#include +#include + +#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; +} diff --git a/images/Makefile.am b/images/Makefile.am index ff8d46f..7f35b75 100644 --- a/images/Makefile.am +++ b/images/Makefile.am @@ -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 diff --git a/po/POTFILES.in b/po/POTFILES.in index a5a27fa..aebe450 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -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 diff --git a/src/MAX_PROC_NR b/src/MAX_PROC_NR index f06fa6c..77f8323 100644 --- a/src/MAX_PROC_NR +++ b/src/MAX_PROC_NR @@ -1 +1 @@ -241 +243 diff --git a/src/generator.ml b/src/generator.ml index 77fa053..b274411 100755 --- a/src/generator.ml +++ b/src/generator.ml @@ -4520,6 +4520,22 @@ There is no comprehensive help for this command. You have to look at the file 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 +to C."); + + ("base64_out", (RErr, [Pathname "filename"; FileOut "base64file"]), 243, [], + [], + "download file and encode as base64", + "\ +This command downloads the contents of C, writing +it out to local file C encoded as base64."); + ] let all_functions = non_daemon_functions @ daemon_functions -- 1.8.3.1