summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Jones <rjones@redhat.com>2009-04-20 15:54:22 +0100
committerRichard Jones <rjones@redhat.com>2009-04-20 15:54:22 +0100
commit0232e722826cfda0f6042da983f9eb871f24e946 (patch)
treee08a414ae15cc70f60ed6275231f9ae050a033fe
parent11350529fee2dbbcfda333bbe10d72f023dc2109 (diff)
downloadlibguestfs-0232e722826cfda0f6042da983f9eb871f24e946.tar.gz
libguestfs-0232e722826cfda0f6042da983f9eb871f24e946.tar.xz
libguestfs-0232e722826cfda0f6042da983f9eb871f24e946.zip
Added tar-in, tar-out, tgz-in, tgz-out commands.
-rw-r--r--HACKING2
-rw-r--r--daemon/Makefile.am1
-rw-r--r--daemon/actions.h4
-rw-r--r--daemon/stubs.c108
-rw-r--r--daemon/tar.c279
-rw-r--r--fish/cmds.c92
-rw-r--r--fish/completion.c4
-rw-r--r--guestfish-actions.pod44
-rw-r--r--guestfs-actions.pod52
-rw-r--r--images/Makefile.am5
-rw-r--r--images/helloworld.tarbin0 -> 10240 bytes
-rw-r--r--images/helloworld.tar.gzbin0 -> 190 bytes
-rw-r--r--ocaml/guestfs.ml4
-rw-r--r--ocaml/guestfs.mli12
-rw-r--r--ocaml/guestfs_c_actions.c96
-rw-r--r--perl/Guestfs.xs48
-rw-r--r--perl/lib/Sys/Guestfs.pm28
-rw-r--r--python/guestfs-py.c108
-rw-r--r--python/guestfs.py32
-rw-r--r--ruby/ext/guestfs/_guestfs.c108
-rwxr-xr-xsrc/generator.ml108
-rw-r--r--src/guestfs-actions.c360
-rw-r--r--src/guestfs-actions.h4
-rw-r--r--src/guestfs_protocol.c40
-rw-r--r--src/guestfs_protocol.h34
-rw-r--r--src/guestfs_protocol.x20
-rw-r--r--tests.c214
27 files changed, 1734 insertions, 73 deletions
diff --git a/HACKING b/HACKING
index 1c2b20c1..85d094b3 100644
--- a/HACKING
+++ b/HACKING
@@ -44,6 +44,8 @@ images/
Some guest images to test against. These are gzipped to save
space. You have to unzip them before use.
+ Also contains some files used by the test suite.
+
m4/
M4 macros used by autoconf.
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index 18866393..4f7ce24d 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -36,6 +36,7 @@ guestfsd_SOURCES = \
stat.c \
stubs.c \
sync.c \
+ tar.c \
tune2fs.c \
upload.c \
../src/guestfs_protocol.h \
diff --git a/daemon/actions.h b/daemon/actions.h
index cffd8efa..d55f4930 100644
--- a/daemon/actions.h
+++ b/daemon/actions.h
@@ -89,3 +89,7 @@ extern int do_blockdev_rereadpt (const char *device);
extern int do_upload (const char *remotefilename);
extern int do_download (const char *remotefilename);
extern char *do_checksum (const char *csumtype, const char *path);
+extern int do_tar_in (const char *directory);
+extern int do_tar_out (const char *directory);
+extern int do_tgz_in (const char *directory);
+extern int do_tgz_out (const char *directory);
diff --git a/daemon/stubs.c b/daemon/stubs.c
index 30394049..82016412 100644
--- a/daemon/stubs.c
+++ b/daemon/stubs.c
@@ -1661,6 +1661,102 @@ done:
xdr_free ((xdrproc_t) xdr_guestfs_checksum_args, (char *) &args);
}
+static void tar_in_stub (XDR *xdr_in)
+{
+ int r;
+ struct guestfs_tar_in_args args;
+ const char *directory;
+
+ memset (&args, 0, sizeof args);
+
+ if (!xdr_guestfs_tar_in_args (xdr_in, &args)) {
+ reply_with_error ("%s: daemon failed to decode procedure arguments", "tar_in");
+ return;
+ }
+ directory = args.directory;
+
+ r = do_tar_in (directory);
+ if (r == -1)
+ /* do_tar_in has already called reply_with_error */
+ goto done;
+
+ reply (NULL, NULL);
+done:
+ xdr_free ((xdrproc_t) xdr_guestfs_tar_in_args, (char *) &args);
+}
+
+static void tar_out_stub (XDR *xdr_in)
+{
+ int r;
+ struct guestfs_tar_out_args args;
+ const char *directory;
+
+ memset (&args, 0, sizeof args);
+
+ if (!xdr_guestfs_tar_out_args (xdr_in, &args)) {
+ reply_with_error ("%s: daemon failed to decode procedure arguments", "tar_out");
+ return;
+ }
+ directory = args.directory;
+
+ r = do_tar_out (directory);
+ if (r == -1)
+ /* do_tar_out has already called reply_with_error */
+ goto done;
+
+ /* do_tar_out has already sent a reply */
+done:
+ xdr_free ((xdrproc_t) xdr_guestfs_tar_out_args, (char *) &args);
+}
+
+static void tgz_in_stub (XDR *xdr_in)
+{
+ int r;
+ struct guestfs_tgz_in_args args;
+ const char *directory;
+
+ memset (&args, 0, sizeof args);
+
+ if (!xdr_guestfs_tgz_in_args (xdr_in, &args)) {
+ reply_with_error ("%s: daemon failed to decode procedure arguments", "tgz_in");
+ return;
+ }
+ directory = args.directory;
+
+ r = do_tgz_in (directory);
+ if (r == -1)
+ /* do_tgz_in has already called reply_with_error */
+ goto done;
+
+ reply (NULL, NULL);
+done:
+ xdr_free ((xdrproc_t) xdr_guestfs_tgz_in_args, (char *) &args);
+}
+
+static void tgz_out_stub (XDR *xdr_in)
+{
+ int r;
+ struct guestfs_tgz_out_args args;
+ const char *directory;
+
+ memset (&args, 0, sizeof args);
+
+ if (!xdr_guestfs_tgz_out_args (xdr_in, &args)) {
+ reply_with_error ("%s: daemon failed to decode procedure arguments", "tgz_out");
+ return;
+ }
+ directory = args.directory;
+
+ r = do_tgz_out (directory);
+ if (r == -1)
+ /* do_tgz_out has already called reply_with_error */
+ goto done;
+
+ /* do_tgz_out has already sent a reply */
+done:
+ xdr_free ((xdrproc_t) xdr_guestfs_tgz_out_args, (char *) &args);
+}
+
void dispatch_incoming_message (XDR *xdr_in)
{
switch (proc_nr) {
@@ -1868,6 +1964,18 @@ void dispatch_incoming_message (XDR *xdr_in)
case GUESTFS_PROC_CHECKSUM:
checksum_stub (xdr_in);
break;
+ case GUESTFS_PROC_TAR_IN:
+ tar_in_stub (xdr_in);
+ break;
+ case GUESTFS_PROC_TAR_OUT:
+ tar_out_stub (xdr_in);
+ break;
+ case GUESTFS_PROC_TGZ_IN:
+ tgz_in_stub (xdr_in);
+ break;
+ case GUESTFS_PROC_TGZ_OUT:
+ tgz_out_stub (xdr_in);
+ break;
default:
reply_with_error ("dispatch_incoming_message: unknown procedure number %d", proc_nr);
}
diff --git a/daemon/tar.c b/daemon/tar.c
new file mode 100644
index 00000000..ecf919db
--- /dev/null
+++ b/daemon/tar.c
@@ -0,0 +1,279 @@
+/* libguestfs - the guestfsd daemon
+ * Copyright (C) 2009 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
+fwrite_cb (void *fp_ptr, const void *buf, int len)
+{
+ FILE *fp = *(FILE **)fp_ptr;
+ return fwrite (buf, len, 1, fp) == 1 ? 0 : -1;
+}
+
+/* Has one FileIn parameter. */
+int
+do_tar_in (const char *dir)
+{
+ int err, r, len;
+ FILE *fp;
+ char *cmd;
+
+ if (!root_mounted || dir[0] != '/') {
+ cancel_receive ();
+ reply_with_error ("tar-in: root must be mounted and path must be absolute");
+ return -1;
+ }
+
+ /* "tar -C /sysroot%s -xf -" but we have to quote the dir. */
+ len = 2 * strlen (dir) + 32;
+ cmd = malloc (len);
+ if (!cmd) {
+ err = errno;
+ cancel_receive ();
+ errno = err;
+ reply_with_perror ("malloc");
+ return -1;
+ }
+ strcpy (cmd, "tar -C /sysroot");
+ shell_quote (cmd+15, len-15, dir);
+ strcat (cmd, " -xf -");
+
+ fp = popen (cmd, "w");
+ if (fp == NULL) {
+ err = errno;
+ cancel_receive ();
+ errno = err;
+ reply_with_perror ("%s", cmd);
+ return -1;
+ }
+
+ r = receive_file (fwrite_cb, &fp);
+ if (r == -1) { /* write error */
+ err = errno;
+ cancel_receive ();
+ errno = err;
+ reply_with_perror ("write: %s", dir);
+ pclose (fp);
+ return -1;
+ }
+ if (r == -2) { /* cancellation from library */
+ pclose (fp);
+ /* Do NOT send any error. */
+ return -1;
+ }
+
+ if (pclose (fp) == -1) {
+ err = errno;
+ cancel_receive ();
+ errno = err;
+ reply_with_perror ("pclose: %s", dir);
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Has one FileOut parameter. */
+int
+do_tar_out (const char *dir)
+{
+ int r, len;
+ FILE *fp;
+ char *cmd;
+ char buf[GUESTFS_MAX_CHUNK_SIZE];
+
+ NEED_ROOT (-1);
+ ABS_PATH (dir, -1);
+
+ /* "tar -C /sysroot%s -cf - ." but we have to quote the dir. */
+ len = 2 * strlen (dir) + 32;
+ cmd = malloc (len);
+ if (!cmd) {
+ reply_with_perror ("malloc");
+ return -1;
+ }
+ strcpy (cmd, "tar -C /sysroot");
+ shell_quote (cmd+15, len-15, dir);
+ strcat (cmd, " -cf - .");
+
+ fp = popen (cmd, "r");
+ if (fp == NULL) {
+ reply_with_perror ("%s", cmd);
+ 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 = fread (buf, 1, sizeof buf, fp)) > 0) {
+ if (send_file_write (buf, r) < 0) {
+ pclose (fp);
+ return -1;
+ }
+ }
+
+ if (r == -1) {
+ perror (dir);
+ send_file_end (1); /* Cancel. */
+ pclose (fp);
+ return -1;
+ }
+
+ if (pclose (fp) == -1) {
+ perror (dir);
+ send_file_end (1); /* Cancel. */
+ return -1;
+ }
+
+ send_file_end (0); /* Normal end of file. */
+ return 0;
+}
+
+/* Has one FileIn parameter. */
+int
+do_tgz_in (const char *dir)
+{
+ int err, r, len;
+ FILE *fp;
+ char *cmd;
+
+ if (!root_mounted || dir[0] != '/') {
+ cancel_receive ();
+ reply_with_error ("tar-in: root must be mounted and path must be absolute");
+ return -1;
+ }
+
+ /* "tar -C /sysroot%s -zxf -" but we have to quote the dir. */
+ len = 2 * strlen (dir) + 32;
+ cmd = malloc (len);
+ if (!cmd) {
+ err = errno;
+ cancel_receive ();
+ errno = err;
+ reply_with_perror ("malloc");
+ return -1;
+ }
+ strcpy (cmd, "tar -C /sysroot");
+ shell_quote (cmd+15, len-15, dir);
+ strcat (cmd, " -zxf -");
+
+ fp = popen (cmd, "w");
+ if (fp == NULL) {
+ err = errno;
+ cancel_receive ();
+ errno = err;
+ reply_with_perror ("%s", cmd);
+ return -1;
+ }
+
+ r = receive_file (fwrite_cb, &fp);
+ if (r == -1) { /* write error */
+ err = errno;
+ cancel_receive ();
+ errno = err;
+ reply_with_perror ("write: %s", dir);
+ pclose (fp);
+ return -1;
+ }
+ if (r == -2) { /* cancellation from library */
+ pclose (fp);
+ /* Do NOT send any error. */
+ return -1;
+ }
+
+ if (pclose (fp) == -1) {
+ err = errno;
+ cancel_receive ();
+ errno = err;
+ reply_with_perror ("pclose: %s", dir);
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Has one FileOut parameter. */
+int
+do_tgz_out (const char *dir)
+{
+ int r, len;
+ FILE *fp;
+ char *cmd;
+ char buf[GUESTFS_MAX_CHUNK_SIZE];
+
+ NEED_ROOT (-1);
+ ABS_PATH (dir, -1);
+
+ /* "tar -C /sysroot%s -zcf - ." but we have to quote the dir. */
+ len = 2 * strlen (dir) + 32;
+ cmd = malloc (len);
+ if (!cmd) {
+ reply_with_perror ("malloc");
+ return -1;
+ }
+ strcpy (cmd, "tar -C /sysroot");
+ shell_quote (cmd+15, len-15, dir);
+ strcat (cmd, " -zcf - .");
+
+ fp = popen (cmd, "r");
+ if (fp == NULL) {
+ reply_with_perror ("%s", cmd);
+ 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 = fread (buf, 1, sizeof buf, fp)) > 0) {
+ if (send_file_write (buf, r) < 0) {
+ pclose (fp);
+ return -1;
+ }
+ }
+
+ if (r == -1) {
+ perror (dir);
+ send_file_end (1); /* Cancel. */
+ pclose (fp);
+ return -1;
+ }
+
+ if (pclose (fp) == -1) {
+ perror (dir);
+ send_file_end (1); /* Cancel. */
+ return -1;
+ }
+
+ send_file_end (0); /* Normal end of file. */
+ return 0;
+}
diff --git a/fish/cmds.c b/fish/cmds.c
index dd574f24..82be2614 100644
--- a/fish/cmds.c
+++ b/fish/cmds.c
@@ -106,6 +106,10 @@ void list_commands (void)
printf ("%-20s %s\n", "stat", "get file information");
printf ("%-20s %s\n", "statvfs", "get file system statistics");
printf ("%-20s %s\n", "sync", "sync disks, writes are flushed through to the disk image");
+ printf ("%-20s %s\n", "tar-in", "unpack tarfile to directory");
+ printf ("%-20s %s\n", "tar-out", "pack directory into tarfile");
+ printf ("%-20s %s\n", "tgz-in", "unpack compressed tarball to directory");
+ printf ("%-20s %s\n", "tgz-out", "pack directory into compressed tarball");
printf ("%-20s %s\n", "touch", "update file timestamps or create a new file");
printf ("%-20s %s\n", "tune2fs-l", "get ext2/ext3 superblock details");
printf ("%-20s %s\n", "umount", "unmount a filesystem");
@@ -372,6 +376,18 @@ void display_command (const char *cmd)
if (strcasecmp (cmd, "checksum") == 0)
pod2text ("checksum - compute MD5, SHAx or CRC checksum of file", " checksum <csumtype> <path>\n\nThis call computes the MD5, SHAx or CRC checksum of the\nfile named C<path>.\n\nThe type of checksum to compute is given by the C<csumtype>\nparameter which must have one of the following values:\n\n=over 4\n\n=item C<crc>\n\nCompute the cyclic redundancy check (CRC) specified by POSIX\nfor the C<cksum> command.\n\n=item C<md5>\n\nCompute the MD5 hash (using the C<md5sum> program).\n\n=item C<sha1>\n\nCompute the SHA1 hash (using the C<sha1sum> program).\n\n=item C<sha224>\n\nCompute the SHA224 hash (using the C<sha224sum> program).\n\n=item C<sha256>\n\nCompute the SHA256 hash (using the C<sha256sum> program).\n\n=item C<sha384>\n\nCompute the SHA384 hash (using the C<sha384sum> program).\n\n=item C<sha512>\n\nCompute the SHA512 hash (using the C<sha512sum> program).\n\n=back\n\nThe checksum is returned as a printable string.");
else
+ if (strcasecmp (cmd, "tar_in") == 0 || strcasecmp (cmd, "tar-in") == 0)
+ pod2text ("tar-in - unpack tarfile to directory", " tar-in <tarfile> <directory>\n\nThis command uploads and unpacks local file C<tarfile> (an\nI<uncompressed> tar file) into C<directory>.\n\nTo upload a compressed tarball, use C<tgz_in>.");
+ else
+ if (strcasecmp (cmd, "tar_out") == 0 || strcasecmp (cmd, "tar-out") == 0)
+ pod2text ("tar-out - pack directory into tarfile", " tar-out <directory> <tarfile>\n\nThis command packs the contents of C<directory> and downloads\nit to local file C<tarfile>.\n\nTo download a compressed tarball, use C<tgz_out>.");
+ else
+ if (strcasecmp (cmd, "tgz_in") == 0 || strcasecmp (cmd, "tgz-in") == 0)
+ pod2text ("tgz-in - unpack compressed tarball to directory", " tgz-in <tarball> <directory>\n\nThis command uploads and unpacks local file C<tarball> (a\nI<gzip compressed> tar file) into C<directory>.\n\nTo upload an uncompressed tarball, use C<tar_in>.");
+ else
+ if (strcasecmp (cmd, "tgz_out") == 0 || strcasecmp (cmd, "tgz-out") == 0)
+ pod2text ("tgz-out - pack directory into compressed tarball", " tgz-out <directory> <tarball>\n\nThis command packs the contents of C<directory> and downloads\nit to local file C<tarball>.\n\nTo download an uncompressed tarball, use C<tar_out>.");
+ else
display_builtin_command (cmd);
}
@@ -1801,6 +1817,70 @@ static int run_checksum (const char *cmd, int argc, char *argv[])
return 0;
}
+static int run_tar_in (const char *cmd, int argc, char *argv[])
+{
+ int r;
+ const char *tarfile;
+ const char *directory;
+ if (argc != 2) {
+ fprintf (stderr, "%s should have 2 parameter(s)\n", cmd);
+ fprintf (stderr, "type 'help %s' for help on %s\n", cmd, cmd);
+ return -1;
+ }
+ tarfile = strcmp (argv[0], "-") != 0 ? argv[0] : "/dev/stdin";
+ directory = argv[1];
+ r = guestfs_tar_in (g, tarfile, directory);
+ return r;
+}
+
+static int run_tar_out (const char *cmd, int argc, char *argv[])
+{
+ int r;
+ const char *directory;
+ const char *tarfile;
+ if (argc != 2) {
+ fprintf (stderr, "%s should have 2 parameter(s)\n", cmd);
+ fprintf (stderr, "type 'help %s' for help on %s\n", cmd, cmd);
+ return -1;
+ }
+ directory = argv[0];
+ tarfile = strcmp (argv[1], "-") != 0 ? argv[1] : "/dev/stdout";
+ r = guestfs_tar_out (g, directory, tarfile);
+ return r;
+}
+
+static int run_tgz_in (const char *cmd, int argc, char *argv[])
+{
+ int r;
+ const char *tarball;
+ const char *directory;
+ if (argc != 2) {
+ fprintf (stderr, "%s should have 2 parameter(s)\n", cmd);
+ fprintf (stderr, "type 'help %s' for help on %s\n", cmd, cmd);
+ return -1;
+ }
+ tarball = strcmp (argv[0], "-") != 0 ? argv[0] : "/dev/stdin";
+ directory = argv[1];
+ r = guestfs_tgz_in (g, tarball, directory);
+ return r;
+}
+
+static int run_tgz_out (const char *cmd, int argc, char *argv[])
+{
+ int r;
+ const char *directory;
+ const char *tarball;
+ if (argc != 2) {
+ fprintf (stderr, "%s should have 2 parameter(s)\n", cmd);
+ fprintf (stderr, "type 'help %s' for help on %s\n", cmd, cmd);
+ return -1;
+ }
+ directory = argv[0];
+ tarball = strcmp (argv[1], "-") != 0 ? argv[1] : "/dev/stdout";
+ r = guestfs_tgz_out (g, directory, tarball);
+ return r;
+}
+
int run_action (const char *cmd, int argc, char *argv[])
{
if (strcasecmp (cmd, "launch") == 0 || strcasecmp (cmd, "run") == 0)
@@ -2055,6 +2135,18 @@ int run_action (const char *cmd, int argc, char *argv[])
if (strcasecmp (cmd, "checksum") == 0)
return run_checksum (cmd, argc, argv);
else
+ if (strcasecmp (cmd, "tar_in") == 0 || strcasecmp (cmd, "tar-in") == 0)
+ return run_tar_in (cmd, argc, argv);
+ else
+ if (strcasecmp (cmd, "tar_out") == 0 || strcasecmp (cmd, "tar-out") == 0)
+ return run_tar_out (cmd, argc, argv);
+ else
+ if (strcasecmp (cmd, "tgz_in") == 0 || strcasecmp (cmd, "tgz-in") == 0)
+ return run_tgz_in (cmd, argc, argv);
+ else
+ if (strcasecmp (cmd, "tgz_out") == 0 || strcasecmp (cmd, "tgz-out") == 0)
+ return run_tgz_out (cmd, argc, argv);
+ else
{
fprintf (stderr, "%s: unknown command\n", cmd);
return -1;
diff --git a/fish/completion.c b/fish/completion.c
index 49f912b9..44cfb9e5 100644
--- a/fish/completion.c
+++ b/fish/completion.c
@@ -114,6 +114,10 @@ static const char *commands[] = {
"stat",
"statvfs",
"sync",
+ "tar-in",
+ "tar-out",
+ "tgz-in",
+ "tgz-out",
"touch",
"tune2fs-l",
"umount",
diff --git a/guestfish-actions.pod b/guestfish-actions.pod
index 78cb4b77..da4bbaeb 100644
--- a/guestfish-actions.pod
+++ b/guestfish-actions.pod
@@ -825,6 +825,50 @@ underlying disk image.
You should always call this if you have modified a disk image, before
closing the handle.
+=head2 tar-in
+
+ tar-in (tarfile|-) directory
+
+This command uploads and unpacks local file C<tarfile> (an
+I<uncompressed> tar file) into C<directory>.
+
+To upload a compressed tarball, use C<tgz_in>.
+
+Use C<-> instead of a filename to read/write from stdin/stdout.
+
+=head2 tar-out
+
+ tar-out directory (tarfile|-)
+
+This command packs the contents of C<directory> and downloads
+it to local file C<tarfile>.
+
+To download a compressed tarball, use C<tgz_out>.
+
+Use C<-> instead of a filename to read/write from stdin/stdout.
+
+=head2 tgz-in
+
+ tgz-in (tarball|-) directory
+
+This command uploads and unpacks local file C<tarball> (a
+I<gzip compressed> tar file) into C<directory>.
+
+To upload an uncompressed tarball, use C<tar_in>.
+
+Use C<-> instead of a filename to read/write from stdin/stdout.
+
+=head2 tgz-out
+
+ tgz-out directory (tarball|-)
+
+This command packs the contents of C<directory> and downloads
+it to local file C<tarball>.
+
+To download an uncompressed tarball, use C<tar_out>.
+
+Use C<-> instead of a filename to read/write from stdin/stdout.
+
=head2 touch
touch path
diff --git a/guestfs-actions.pod b/guestfs-actions.pod
index b901919d..dcffc831 100644
--- a/guestfs-actions.pod
+++ b/guestfs-actions.pod
@@ -1115,6 +1115,58 @@ closing the handle.
This function returns 0 on success or -1 on error.
+=head2 guestfs_tar_in
+
+ int guestfs_tar_in (guestfs_h *handle,
+ const char *tarfile,
+ const char *directory);
+
+This command uploads and unpacks local file C<tarfile> (an
+I<uncompressed> tar file) into C<directory>.
+
+To upload a compressed tarball, use C<guestfs_tgz_in>.
+
+This function returns 0 on success or -1 on error.
+
+=head2 guestfs_tar_out
+
+ int guestfs_tar_out (guestfs_h *handle,
+ const char *directory,
+ const char *tarfile);
+
+This command packs the contents of C<directory> and downloads
+it to local file C<tarfile>.
+
+To download a compressed tarball, use C<guestfs_tgz_out>.
+
+This function returns 0 on success or -1 on error.
+
+=head2 guestfs_tgz_in
+
+ int guestfs_tgz_in (guestfs_h *handle,
+ const char *tarball,
+ const char *directory);
+
+This command uploads and unpacks local file C<tarball> (a
+I<gzip compressed> tar file) into C<directory>.
+
+To upload an uncompressed tarball, use C<guestfs_tar_in>.
+
+This function returns 0 on success or -1 on error.
+
+=head2 guestfs_tgz_out
+
+ int guestfs_tgz_out (guestfs_h *handle,
+ const char *directory,
+ const char *tarball);
+
+This command packs the contents of C<directory> and downloads
+it to local file C<tarball>.
+
+To download an uncompressed tarball, use C<guestfs_tar_out>.
+
+This function returns 0 on success or -1 on error.
+
=head2 guestfs_touch
int guestfs_touch (guestfs_h *handle,
diff --git a/images/Makefile.am b/images/Makefile.am
index e9ea2f44..d5272e9d 100644
--- a/images/Makefile.am
+++ b/images/Makefile.am
@@ -15,6 +15,9 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-EXTRA_DIST = mbr-ext2-empty.img.gz
+EXTRA_DIST = \
+ helloworld.tar \
+ helloworld.tar.gz \
+ mbr-ext2-empty.img.gz
CLEANFILES = *~
diff --git a/images/helloworld.tar b/images/helloworld.tar
new file mode 100644
index 00000000..191a31b2
--- /dev/null
+++ b/images/helloworld.tar
Binary files differ
diff --git a/images/helloworld.tar.gz b/images/helloworld.tar.gz
new file mode 100644
index 00000000..9d36cc97
--- /dev/null
+++ b/images/helloworld.tar.gz
Binary files differ
diff --git a/ocaml/guestfs.ml b/ocaml/guestfs.ml
index 337555c9..3ca33f7b 100644
--- a/ocaml/guestfs.ml
+++ b/ocaml/guestfs.ml
@@ -202,3 +202,7 @@ external blockdev_rereadpt : t -> string -> unit = "ocaml_guestfs_blockdev_rerea
external upload : t -> string -> string -> unit = "ocaml_guestfs_upload"
external download : t -> string -> string -> unit = "ocaml_guestfs_download"
external checksum : t -> string -> string -> string = "ocaml_guestfs_checksum"
+external tar_in : t -> string -> string -> unit = "ocaml_guestfs_tar_in"
+external tar_out : t -> string -> string -> unit = "ocaml_guestfs_tar_out"
+external tgz_in : t -> string -> string -> unit = "ocaml_guestfs_tgz_in"
+external tgz_out : t -> string -> string -> unit = "ocaml_guestfs_tgz_out"
diff --git a/ocaml/guestfs.mli b/ocaml/guestfs.mli
index 4fd05dad..629e443e 100644
--- a/ocaml/guestfs.mli
+++ b/ocaml/guestfs.mli
@@ -385,3 +385,15 @@ val download : t -> string -> string -> unit
val checksum : t -> string -> string -> string
(** compute MD5, SHAx or CRC checksum of file *)
+val tar_in : t -> string -> string -> unit
+(** unpack tarfile to directory *)
+
+val tar_out : t -> string -> string -> unit
+(** pack directory into tarfile *)
+
+val tgz_in : t -> string -> string -> unit
+(** unpack compressed tarball to directory *)
+
+val tgz_out : t -> string -> string -> unit
+(** pack directory into compressed tarball *)
+
diff --git a/ocaml/guestfs_c_actions.c b/ocaml/guestfs_c_actions.c
index 882d5052..cfcf4e4c 100644
--- a/ocaml/guestfs_c_actions.c
+++ b/ocaml/guestfs_c_actions.c
@@ -2392,3 +2392,99 @@ ocaml_guestfs_checksum (value gv, value csumtypev, value pathv)
CAMLreturn (rv);
}
+CAMLprim value
+ocaml_guestfs_tar_in (value gv, value tarfilev, value directoryv)
+{
+ CAMLparam3 (gv, tarfilev, directoryv);
+ CAMLlocal1 (rv);
+
+ guestfs_h *g = Guestfs_val (gv);
+ if (g == NULL)
+ caml_failwith ("tar_in: used handle after closing it");
+
+ const char *tarfile = String_val (tarfilev);
+ const char *directory = String_val (directoryv);
+ int r;
+
+ caml_enter_blocking_section ();
+ r = guestfs_tar_in (g, tarfile, directory);
+ caml_leave_blocking_section ();
+ if (r == -1)
+ ocaml_guestfs_raise_error (g, "tar_in");
+
+ rv = Val_unit;
+ CAMLreturn (rv);
+}
+
+CAMLprim value
+ocaml_guestfs_tar_out (value gv, value directoryv, value tarfilev)
+{
+ CAMLparam3 (gv, directoryv, tarfilev);
+ CAMLlocal1 (rv);
+
+ guestfs_h *g = Guestfs_val (gv);
+ if (g == NULL)
+ caml_failwith ("tar_out: used handle after closing it");
+
+ const char *directory = String_val (directoryv);
+ const char *tarfile = String_val (tarfilev);
+ int r;
+
+ caml_enter_blocking_section ();
+ r = guestfs_tar_out (g, directory, tarfile);
+ caml_leave_blocking_section ();
+ if (r == -1)
+ ocaml_guestfs_raise_error (g, "tar_out");
+
+ rv = Val_unit;
+ CAMLreturn (rv);
+}
+
+CAMLprim value
+ocaml_guestfs_tgz_in (value gv, value tarballv, value directoryv)
+{
+ CAMLparam3 (gv, tarballv, directoryv);
+ CAMLlocal1 (rv);
+
+ guestfs_h *g = Guestfs_val (gv);
+ if (g == NULL)
+ caml_failwith ("tgz_in: used handle after closing it");
+
+ const char *tarball = String_val (tarballv);
+ const char *directory = String_val (directoryv);
+ int r;
+
+ caml_enter_blocking_section ();
+ r = guestfs_tgz_in (g, tarball, directory);
+ caml_leave_blocking_section ();
+ if (r == -1)
+ ocaml_guestfs_raise_error (g, "tgz_in");
+
+ rv = Val_unit;
+ CAMLreturn (rv);
+}
+
+CAMLprim value
+ocaml_guestfs_tgz_out (value gv, value directoryv, value tarballv)
+{
+ CAMLparam3 (gv, directoryv, tarballv);
+ CAMLlocal1 (rv);
+
+ guestfs_h *g = Guestfs_val (gv);
+ if (g == NULL)
+ caml_failwith ("tgz_out: used handle after closing it");
+
+ const char *directory = String_val (directoryv);
+ const char *tarball = String_val (tarballv);
+ int r;
+
+ caml_enter_blocking_section ();
+ r = guestfs_tgz_out (g, directory, tarball);
+ caml_leave_blocking_section ();
+ if (r == -1)
+ ocaml_guestfs_raise_error (g, "tgz_out");
+
+ rv = Val_unit;
+ CAMLreturn (rv);
+}
+
diff --git a/perl/Guestfs.xs b/perl/Guestfs.xs
index 7d9b3dfd..63dce749 100644
--- a/perl/Guestfs.xs
+++ b/perl/Guestfs.xs
@@ -1357,3 +1357,51 @@ PREINIT:
OUTPUT:
RETVAL
+void
+tar_in (g, tarfile, directory)
+ guestfs_h *g;
+ char *tarfile;
+ char *directory;
+PREINIT:
+ int r;
+ PPCODE:
+ r = guestfs_tar_in (g, tarfile, directory);
+ if (r == -1)
+ croak ("tar_in: %s", guestfs_last_error (g));
+
+void
+tar_out (g, directory, tarfile)
+ guestfs_h *g;
+ char *directory;
+ char *tarfile;
+PREINIT:
+ int r;
+ PPCODE:
+ r = guestfs_tar_out (g, directory, tarfile);
+ if (r == -1)
+ croak ("tar_out: %s", guestfs_last_error (g));
+
+void
+tgz_in (g, tarball, directory)
+ guestfs_h *g;
+ char *tarball;
+ char *directory;
+PREINIT:
+ int r;
+ PPCODE:
+ r = guestfs_tgz_in (g, tarball, directory);
+ if (r == -1)
+ croak ("tgz_in: %s", guestfs_last_error (g));
+
+void
+tgz_out (g, directory, tarball)
+ guestfs_h *g;
+ char *directory;
+ char *tarball;
+PREINIT:
+ int r;
+ PPCODE:
+ r = guestfs_tgz_out (g, directory, tarball);
+ if (r == -1)
+ croak ("tgz_out: %s", guestfs_last_error (g));
+
diff --git a/perl/lib/Sys/Guestfs.pm b/perl/lib/Sys/Guestfs.pm
index ad200881..d16077e5 100644
--- a/perl/lib/Sys/Guestfs.pm
+++ b/perl/lib/Sys/Guestfs.pm
@@ -780,6 +780,34 @@ underlying disk image.
You should always call this if you have modified a disk image, before
closing the handle.
+=item $h->tar_in ($tarfile, $directory);
+
+This command uploads and unpacks local file C<tarfile> (an
+I<uncompressed> tar file) into C<directory>.
+
+To upload a compressed tarball, use C<$h-E<gt>tgz_in>.
+
+=item $h->tar_out ($directory, $tarfile);
+
+This command packs the contents of C<directory> and downloads
+it to local file C<tarfile>.
+
+To download a compressed tarball, use C<$h-E<gt>tgz_out>.
+
+=item $h->tgz_in ($tarball, $directory);
+
+This command uploads and unpacks local file C<tarball> (a
+I<gzip compressed> tar file) into C<directory>.
+
+To upload an uncompressed tarball, use C<$h-E<gt>tar_in>.
+
+=item $h->tgz_out ($directory, $tarball);
+
+This command packs the contents of C<directory> and downloads
+it to local file C<tarball>.
+
+To download an uncompressed tarball, use C<$h-E<gt>tar_out>.
+
=item $h->touch ($path);
Touch acts like the L<touch(1)> command. It can be used to
diff --git a/python/guestfs-py.c b/python/guestfs-py.c
index 4d31d9f7..800d21b9 100644
--- a/python/guestfs-py.c
+++ b/python/guestfs-py.c
@@ -2562,6 +2562,110 @@ py_guestfs_checksum (PyObject *self, PyObject *args)
return py_r;
}
+static PyObject *
+py_guestfs_tar_in (PyObject *self, PyObject *args)
+{
+ PyObject *py_g;
+ guestfs_h *g;
+ PyObject *py_r;
+ int r;
+ const char *tarfile;
+ const char *directory;
+
+ if (!PyArg_ParseTuple (args, (char *) "Oss:guestfs_tar_in",
+ &py_g, &tarfile, &directory))
+ return NULL;
+ g = get_handle (py_g);
+
+ r = guestfs_tar_in (g, tarfile, directory);
+ if (r == -1) {
+ PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g));
+ return NULL;
+ }
+
+ Py_INCREF (Py_None);
+ py_r = Py_None;
+ return py_r;
+}
+
+static PyObject *
+py_guestfs_tar_out (PyObject *self, PyObject *args)
+{
+ PyObject *py_g;
+ guestfs_h *g;
+ PyObject *py_r;
+ int r;
+ const char *directory;
+ const char *tarfile;
+
+ if (!PyArg_ParseTuple (args, (char *) "Oss:guestfs_tar_out",
+ &py_g, &directory, &tarfile))
+ return NULL;
+ g = get_handle (py_g);
+
+ r = guestfs_tar_out (g, directory, tarfile);
+ if (r == -1) {
+ PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g));
+ return NULL;
+ }
+
+ Py_INCREF (Py_None);
+ py_r = Py_None;
+ return py_r;
+}
+
+static PyObject *
+py_guestfs_tgz_in (PyObject *self, PyObject *args)
+{
+ PyObject *py_g;
+ guestfs_h *g;
+ PyObject *py_r;
+ int r;
+ const char *tarball;
+ const char *directory;
+
+ if (!PyArg_ParseTuple (args, (char *) "Oss:guestfs_tgz_in",
+ &py_g, &tarball, &directory))
+ return NULL;
+ g = get_handle (py_g);
+
+ r = guestfs_tgz_in (g, tarball, directory);
+ if (r == -1) {
+ PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g));
+ return NULL;
+ }
+
+ Py_INCREF (Py_None);
+ py_r = Py_None;
+ return py_r;
+}
+
+static PyObject *
+py_guestfs_tgz_out (PyObject *self, PyObject *args)
+{
+ PyObject *py_g;
+ guestfs_h *g;
+ PyObject *py_r;
+ int r;
+ const char *directory;
+ const char *tarball;
+
+ if (!PyArg_ParseTuple (args, (char *) "Oss:guestfs_tgz_out",
+ &py_g, &directory, &tarball))
+ return NULL;
+ g = get_handle (py_g);
+
+ r = guestfs_tgz_out (g, directory, tarball);
+ if (r == -1) {
+ PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g));
+ return NULL;
+ }
+
+ Py_INCREF (Py_None);
+ py_r = Py_None;
+ return py_r;
+}
+
static PyMethodDef methods[] = {
{ (char *) "create", py_guestfs_create, METH_VARARGS, NULL },
{ (char *) "close", py_guestfs_close, METH_VARARGS, NULL },
@@ -2652,6 +2756,10 @@ static PyMethodDef methods[] = {
{ (char *) "upload", py_guestfs_upload, METH_VARARGS, NULL },
{ (char *) "download", py_guestfs_download, METH_VARARGS, NULL },
{ (char *) "checksum", py_guestfs_checksum, METH_VARARGS, NULL },
+ { (char *) "tar_in", py_guestfs_tar_in, METH_VARARGS, NULL },
+ { (char *) "tar_out", py_guestfs_tar_out, METH_VARARGS, NULL },
+ { (char *) "tgz_in", py_guestfs_tgz_in, METH_VARARGS, NULL },
+ { (char *) "tgz_out", py_guestfs_tgz_out, METH_VARARGS, NULL },
{ NULL, NULL, 0, NULL }
};
diff --git a/python/guestfs.py b/python/guestfs.py
index 4d71b23c..6417caf4 100644
--- a/python/guestfs.py
+++ b/python/guestfs.py
@@ -997,3 +997,35 @@ class GuestFS:
"""
return libguestfsmod.checksum (self._o, csumtype, path)
+ def tar_in (self, tarfile, directory):
+ u"""This command uploads and unpacks local file "tarfile"
+ (an *uncompressed* tar file) into "directory".
+
+ To upload a compressed tarball, use "g.tgz_in".
+ """
+ return libguestfsmod.tar_in (self._o, tarfile, directory)
+
+ def tar_out (self, directory, tarfile):
+ u"""This command packs the contents of "directory" and
+ downloads it to local file "tarfile".
+
+ To download a compressed tarball, use "g.tgz_out".
+ """
+ return libguestfsmod.tar_out (self._o, directory, tarfile)
+
+ def tgz_in (self, tarball, directory):
+ u"""This command uploads and unpacks local file "tarball" (a
+ *gzip compressed* tar file) into "directory".
+
+ To upload an uncompressed tarball, use "g.tar_in".
+ """
+ return libguestfsmod.tgz_in (self._o, tarball, directory)
+
+ def tgz_out (self, directory, tarball):
+ u"""This command packs the contents of "directory" and
+ downloads it to local file "tarball".
+
+ To download an uncompressed tarball, use "g.tar_out".
+ """
+ return libguestfsmod.tgz_out (self._o, directory, tarball)
+
diff --git a/ruby/ext/guestfs/_guestfs.c b/ruby/ext/guestfs/_guestfs.c
index 3861d9b7..9971228f 100644
--- a/ruby/ext/guestfs/_guestfs.c
+++ b/ruby/ext/guestfs/_guestfs.c
@@ -2093,6 +2093,106 @@ static VALUE ruby_guestfs_checksum (VALUE gv, VALUE csumtypev, VALUE pathv)
return rv;
}
+static VALUE ruby_guestfs_tar_in (VALUE gv, VALUE tarfilev, VALUE directoryv)
+{
+ guestfs_h *g;
+ Data_Get_Struct (gv, guestfs_h, g);
+ if (!g)
+ rb_raise (rb_eArgError, "%s: used handle after closing it", "tar_in");
+
+ const char *tarfile = StringValueCStr (tarfilev);
+ if (!tarfile)
+ rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+ "tarfile", "tar_in");
+ const char *directory = StringValueCStr (directoryv);
+ if (!directory)
+ rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+ "directory", "tar_in");
+
+ int r;
+
+ r = guestfs_tar_in (g, tarfile, directory);
+ if (r == -1)
+ rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+ return Qnil;
+}
+
+static VALUE ruby_guestfs_tar_out (VALUE gv, VALUE directoryv, VALUE tarfilev)
+{
+ guestfs_h *g;
+ Data_Get_Struct (gv, guestfs_h, g);
+ if (!g)
+ rb_raise (rb_eArgError, "%s: used handle after closing it", "tar_out");
+
+ const char *directory = StringValueCStr (directoryv);
+ if (!directory)
+ rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+ "directory", "tar_out");
+ const char *tarfile = StringValueCStr (tarfilev);
+ if (!tarfile)
+ rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+ "tarfile", "tar_out");
+
+ int r;
+
+ r = guestfs_tar_out (g, directory, tarfile);
+ if (r == -1)
+ rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+ return Qnil;
+}
+
+static VALUE ruby_guestfs_tgz_in (VALUE gv, VALUE tarballv, VALUE directoryv)
+{
+ guestfs_h *g;
+ Data_Get_Struct (gv, guestfs_h, g);
+ if (!g)
+ rb_raise (rb_eArgError, "%s: used handle after closing it", "tgz_in");
+
+ const char *tarball = StringValueCStr (tarballv);
+ if (!tarball)
+ rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+ "tarball", "tgz_in");
+ const char *directory = StringValueCStr (directoryv);
+ if (!directory)
+ rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+ "directory", "tgz_in");
+
+ int r;
+
+ r = guestfs_tgz_in (g, tarball, directory);
+ if (r == -1)
+ rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+ return Qnil;
+}
+
+static VALUE ruby_guestfs_tgz_out (VALUE gv, VALUE directoryv, VALUE tarballv)
+{
+ guestfs_h *g;
+ Data_Get_Struct (gv, guestfs_h, g);
+ if (!g)
+ rb_raise (rb_eArgError, "%s: used handle after closing it", "tgz_out");
+
+ const char *directory = StringValueCStr (directoryv);
+ if (!directory)
+ rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+ "directory", "tgz_out");
+ const char *tarball = StringValueCStr (tarballv);
+ if (!tarball)
+ rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+ "tarball", "tgz_out");
+
+ int r;
+
+ r = guestfs_tgz_out (g, directory, tarball);
+ if (r == -1)
+ rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+ return Qnil;
+}
+
/* Initialize the module. */
void Init__guestfs ()
{
@@ -2277,4 +2377,12 @@ void Init__guestfs ()
ruby_guestfs_download, 2);
rb_define_method (c_guestfs, "checksum",
ruby_guestfs_checksum, 2);
+ rb_define_method (c_guestfs, "tar_in",
+ ruby_guestfs_tar_in, 2);
+ rb_define_method (c_guestfs, "tar_out",
+ ruby_guestfs_tar_out, 2);
+ rb_define_method (c_guestfs, "tgz_in",
+ ruby_guestfs_tgz_in, 2);
+ rb_define_method (c_guestfs, "tgz_out",
+ ruby_guestfs_tgz_out, 2);
}
diff --git a/src/generator.ml b/src/generator.ml
index ae1dfe9f..bdd032c8 100755
--- a/src/generator.ml
+++ b/src/generator.ml
@@ -1369,6 +1369,46 @@ Compute the SHA512 hash (using the C<sha512sum> program).
The checksum is returned as a printable string.");
+ ("tar_in", (RErr, [FileIn "tarfile"; String "directory"]), 69, [],
+ [InitBasicFS, TestOutput (
+ [["tar_in"; "images/helloworld.tar"; "/"];
+ ["cat"; "/hello"]], "hello\n")],
+ "unpack tarfile to directory",
+ "\
+This command uploads and unpacks local file C<tarfile> (an
+I<uncompressed> tar file) into C<directory>.
+
+To upload a compressed tarball, use C<guestfs_tgz_in>.");
+
+ ("tar_out", (RErr, [String "directory"; FileOut "tarfile"]), 70, [],
+ [],
+ "pack directory into tarfile",
+ "\
+This command packs the contents of C<directory> and downloads
+it to local file C<tarfile>.
+
+To download a compressed tarball, use C<guestfs_tgz_out>.");
+
+ ("tgz_in", (RErr, [FileIn "tarball"; String "directory"]), 71, [],
+ [InitBasicFS, TestOutput (
+ [["tgz_in"; "images/helloworld.tar.gz"; "/"];
+ ["cat"; "/hello"]], "hello\n")],
+ "unpack compressed tarball to directory",
+ "\
+This command uploads and unpacks local file C<tarball> (a
+I<gzip compressed> tar file) into C<directory>.
+
+To upload an uncompressed tarball, use C<guestfs_tar_in>.");
+
+ ("tgz_out", (RErr, [String "directory"; FileOut "tarball"]), 72, [],
+ [],
+ "pack directory into compressed tarball",
+ "\
+This command packs the contents of C<directory> and downloads
+it to local file C<tarball>.
+
+To download an uncompressed tarball, use C<guestfs_tar_out>.");
+
]
let all_functions = non_daemon_functions @ daemon_functions
@@ -2856,8 +2896,8 @@ int main (int argc, char *argv[])
char c = 0;
int failed = 0;
const char *srcdir;
+ const char *filename;
int fd;
- char buf[256];
int nr_tests, test_num = 0;
no_test_warnings ();
@@ -2872,89 +2912,90 @@ int main (int argc, char *argv[])
srcdir = getenv (\"srcdir\");
if (!srcdir) srcdir = \".\";
- guestfs_set_path (g, srcdir);
+ chdir (srcdir);
+ guestfs_set_path (g, \".\");
- snprintf (buf, sizeof buf, \"%%s/test1.img\", srcdir);
- fd = open (buf, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
+ filename = \"test1.img\";
+ fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
if (fd == -1) {
- perror (buf);
+ perror (filename);
exit (1);
}
if (lseek (fd, %d, SEEK_SET) == -1) {
perror (\"lseek\");
close (fd);
- unlink (buf);
+ unlink (filename);
exit (1);
}
if (write (fd, &c, 1) == -1) {
perror (\"write\");
close (fd);
- unlink (buf);
+ unlink (filename);
exit (1);
}
if (close (fd) == -1) {
- perror (buf);
- unlink (buf);
+ perror (filename);
+ unlink (filename);
exit (1);
}
- if (guestfs_add_drive (g, buf) == -1) {
- printf (\"guestfs_add_drive %%s FAILED\\n\", buf);
+ if (guestfs_add_drive (g, filename) == -1) {
+ printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
exit (1);
}
- snprintf (buf, sizeof buf, \"%%s/test2.img\", srcdir);
- fd = open (buf, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
+ filename = \"test2.img\";
+ fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
if (fd == -1) {
- perror (buf);
+ perror (filename);
exit (1);
}
if (lseek (fd, %d, SEEK_SET) == -1) {
perror (\"lseek\");
close (fd);
- unlink (buf);
+ unlink (filename);
exit (1);
}
if (write (fd, &c, 1) == -1) {
perror (\"write\");
close (fd);
- unlink (buf);
+ unlink (filename);
exit (1);
}
if (close (fd) == -1) {
- perror (buf);
- unlink (buf);
+ perror (filename);
+ unlink (filename);
exit (1);
}
- if (guestfs_add_drive (g, buf) == -1) {
- printf (\"guestfs_add_drive %%s FAILED\\n\", buf);
+ if (guestfs_add_drive (g, filename) == -1) {
+ printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
exit (1);
}
- snprintf (buf, sizeof buf, \"%%s/test3.img\", srcdir);
- fd = open (buf, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
+ filename = \"test3.img\";
+ fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
if (fd == -1) {
- perror (buf);
+ perror (filename);
exit (1);
}
if (lseek (fd, %d, SEEK_SET) == -1) {
perror (\"lseek\");
close (fd);
- unlink (buf);
+ unlink (filename);
exit (1);
}
if (write (fd, &c, 1) == -1) {
perror (\"write\");
close (fd);
- unlink (buf);
+ unlink (filename);
exit (1);
}
if (close (fd) == -1) {
- perror (buf);
- unlink (buf);
+ perror (filename);
+ unlink (filename);
exit (1);
}
- if (guestfs_add_drive (g, buf) == -1) {
- printf (\"guestfs_add_drive %%s FAILED\\n\", buf);
+ if (guestfs_add_drive (g, filename) == -1) {
+ printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
exit (1);
}
@@ -2983,12 +3024,9 @@ int main (int argc, char *argv[])
pr "\n";
pr " guestfs_close (g);\n";
- pr " snprintf (buf, sizeof buf, \"%%s/test1.img\", srcdir);\n";
- pr " unlink (buf);\n";
- pr " snprintf (buf, sizeof buf, \"%%s/test2.img\", srcdir);\n";
- pr " unlink (buf);\n";
- pr " snprintf (buf, sizeof buf, \"%%s/test3.img\", srcdir);\n";
- pr " unlink (buf);\n";
+ pr " unlink (\"test1.img\");\n";
+ pr " unlink (\"test2.img\");\n";
+ pr " unlink (\"test3.img\");\n";
pr "\n";
pr " if (failed > 0) {\n";
diff --git a/src/guestfs-actions.c b/src/guestfs-actions.c
index 5985e41c..efc556ea 100644
--- a/src/guestfs-actions.c
+++ b/src/guestfs-actions.c
@@ -5777,3 +5777,363 @@ char *guestfs_checksum (guestfs_h *g,
return ctx.ret.checksum; /* caller will free */
}
+struct tar_in_ctx {
+ /* This flag is set by the callbacks, so we know we've done
+ * the callbacks as expected, and in the right sequence.
+ * 0 = not called, 1 = send called,
+ * 1001 = reply called.
+ */
+ int cb_sequence;
+ struct guestfs_message_header hdr;
+ struct guestfs_message_error err;
+};
+
+static void tar_in_reply_cb (guestfs_h *g, void *data, XDR *xdr)
+{
+ guestfs_main_loop *ml = guestfs_get_main_loop (g);
+ struct tar_in_ctx *ctx = (struct tar_in_ctx *) data;
+
+ ml->main_loop_quit (ml, g);
+
+ if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
+ error (g, "%s: failed to parse reply header", "guestfs_tar_in");
+ return;
+ }
+ if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
+ if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
+ error (g, "%s: failed to parse reply error", "guestfs_tar_in");
+ return;
+ }
+ goto done;
+ }
+ done:
+ ctx->cb_sequence = 1001;
+}
+
+int guestfs_tar_in (guestfs_h *g,
+ const char *tarfile,
+ const char *directory)
+{
+ struct guestfs_tar_in_args args;
+ struct tar_in_ctx ctx;
+ guestfs_main_loop *ml = guestfs_get_main_loop (g);
+ int serial;
+
+ if (check_state (g, "guestfs_tar_in") == -1) return -1;
+ guestfs_set_busy (g);
+
+ memset (&ctx, 0, sizeof ctx);
+
+ args.directory = (char *) directory;
+ serial = guestfs__send_sync (g, GUESTFS_PROC_TAR_IN,
+ (xdrproc_t) xdr_guestfs_tar_in_args, (char *) &args);
+ if (serial == -1) {
+ guestfs_set_ready (g);
+ return -1;
+ }
+
+ {
+ int r;
+
+ r = guestfs__send_file_sync (g, tarfile);
+ if (r == -1) {
+ guestfs_set_ready (g);
+ return -1;
+ }
+ if (r == -2) /* daemon cancelled */
+ goto read_reply;
+ }
+
+ read_reply:
+ guestfs__switch_to_receiving (g);
+ ctx.cb_sequence = 0;
+ guestfs_set_reply_callback (g, tar_in_reply_cb, &ctx);
+ (void) ml->main_loop_run (ml, g);
+ guestfs_set_reply_callback (g, NULL, NULL);
+ if (ctx.cb_sequence != 1001) {
+ error (g, "%s reply failed, see earlier error messages", "guestfs_tar_in");
+ guestfs_set_ready (g);
+ return -1;
+ }
+
+ if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_TAR_IN, serial) == -1) {
+ guestfs_set_ready (g);
+ return -1;
+ }
+
+ if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
+ error (g, "%s", ctx.err.error_message);
+ guestfs_set_ready (g);
+ return -1;
+ }
+
+ guestfs_set_ready (g);
+ return 0;
+}
+
+struct tar_out_ctx {
+ /* This flag is set by the callbacks, so we know we've done
+ * the callbacks as expected, and in the right sequence.
+ * 0 = not called, 1 = send called,
+ * 1001 = reply called.
+ */
+ int cb_sequence;
+ struct guestfs_message_header hdr;
+ struct guestfs_message_error err;
+};
+
+static void tar_out_reply_cb (guestfs_h *g, void *data, XDR *xdr)
+{
+ guestfs_main_loop *ml = guestfs_get_main_loop (g);
+ struct tar_out_ctx *ctx = (struct tar_out_ctx *) data;
+
+ ml->main_loop_quit (ml, g);
+
+ if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
+ error (g, "%s: failed to parse reply header", "guestfs_tar_out");
+ return;
+ }
+ if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
+ if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
+ error (g, "%s: failed to parse reply error", "guestfs_tar_out");
+ return;
+ }
+ goto done;
+ }
+ done:
+ ctx->cb_sequence = 1001;
+}
+
+int guestfs_tar_out (guestfs_h *g,
+ const char *directory,
+ const char *tarfile)
+{
+ struct guestfs_tar_out_args args;
+ struct tar_out_ctx ctx;
+ guestfs_main_loop *ml = guestfs_get_main_loop (g);
+ int serial;
+
+ if (check_state (g, "guestfs_tar_out") == -1) return -1;
+ guestfs_set_busy (g);
+
+ memset (&ctx, 0, sizeof ctx);
+
+ args.directory = (char *) directory;
+ serial = guestfs__send_sync (g, GUESTFS_PROC_TAR_OUT,
+ (xdrproc_t) xdr_guestfs_tar_out_args, (char *) &args);
+ if (serial == -1) {
+ guestfs_set_ready (g);
+ return -1;
+ }
+
+ guestfs__switch_to_receiving (g);
+ ctx.cb_sequence = 0;
+ guestfs_set_reply_callback (g, tar_out_reply_cb, &ctx);
+ (void) ml->main_loop_run (ml, g);
+ guestfs_set_reply_callback (g, NULL, NULL);
+ if (ctx.cb_sequence != 1001) {
+ error (g, "%s reply failed, see earlier error messages", "guestfs_tar_out");
+ guestfs_set_ready (g);
+ return -1;
+ }
+
+ if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_TAR_OUT, serial) == -1) {
+ guestfs_set_ready (g);
+ return -1;
+ }
+
+ if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
+ error (g, "%s", ctx.err.error_message);
+ guestfs_set_ready (g);
+ return -1;
+ }
+
+ if (guestfs__receive_file_sync (g, tarfile) == -1) {
+ guestfs_set_ready (g);
+ return -1;
+ }
+
+ guestfs_set_ready (g);
+ return 0;
+}
+
+struct tgz_in_ctx {
+ /* This flag is set by the callbacks, so we know we've done
+ * the callbacks as expected, and in the right sequence.
+ * 0 = not called, 1 = send called,
+ * 1001 = reply called.
+ */
+ int cb_sequence;
+ struct guestfs_message_header hdr;
+ struct guestfs_message_error err;
+};
+
+static void tgz_in_reply_cb (guestfs_h *g, void *data, XDR *xdr)
+{
+ guestfs_main_loop *ml = guestfs_get_main_loop (g);
+ struct tgz_in_ctx *ctx = (struct tgz_in_ctx *) data;
+
+ ml->main_loop_quit (ml, g);
+
+ if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
+ error (g, "%s: failed to parse reply header", "guestfs_tgz_in");
+ return;
+ }
+ if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
+ if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
+ error (g, "%s: failed to parse reply error", "guestfs_tgz_in");
+ return;
+ }
+ goto done;
+ }
+ done:
+ ctx->cb_sequence = 1001;
+}
+
+int guestfs_tgz_in (guestfs_h *g,
+ const char *tarball,
+ const char *directory)
+{
+ struct guestfs_tgz_in_args args;
+ struct tgz_in_ctx ctx;
+ guestfs_main_loop *ml = guestfs_get_main_loop (g);
+ int serial;
+
+ if (check_state (g, "guestfs_tgz_in") == -1) return -1;
+ guestfs_set_busy (g);
+
+ memset (&ctx, 0, sizeof ctx);
+
+ args.directory = (char *) directory;
+ serial = guestfs__send_sync (g, GUESTFS_PROC_TGZ_IN,
+ (xdrproc_t) xdr_guestfs_tgz_in_args, (char *) &args);
+ if (serial == -1) {
+ guestfs_set_ready (g);
+ return -1;
+ }
+
+ {
+ int r;
+
+ r = guestfs__send_file_sync (g, tarball);
+ if (r == -1) {
+ guestfs_set_ready (g);
+ return -1;
+ }
+ if (r == -2) /* daemon cancelled */
+ goto read_reply;
+ }
+
+ read_reply:
+ guestfs__switch_to_receiving (g);
+ ctx.cb_sequence = 0;
+ guestfs_set_reply_callback (g, tgz_in_reply_cb, &ctx);
+ (void) ml->main_loop_run (ml, g);
+ guestfs_set_reply_callback (g, NULL, NULL);
+ if (ctx.cb_sequence != 1001) {
+ error (g, "%s reply failed, see earlier error messages", "guestfs_tgz_in");
+ guestfs_set_ready (g);
+ return -1;
+ }
+
+ if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_TGZ_IN, serial) == -1) {
+ guestfs_set_ready (g);
+ return -1;
+ }
+
+ if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
+ error (g, "%s", ctx.err.error_message);
+ guestfs_set_ready (g);
+ return -1;
+ }
+
+ guestfs_set_ready (g);
+ return 0;
+}
+
+struct tgz_out_ctx {
+ /* This flag is set by the callbacks, so we know we've done
+ * the callbacks as expected, and in the right sequence.
+ * 0 = not called, 1 = send called,
+ * 1001 = reply called.
+ */
+ int cb_sequence;
+ struct guestfs_message_header hdr;
+ struct guestfs_message_error err;
+};
+
+static void tgz_out_reply_cb (guestfs_h *g, void *data, XDR *xdr)
+{
+ guestfs_main_loop *ml = guestfs_get_main_loop (g);
+ struct tgz_out_ctx *ctx = (struct tgz_out_ctx *) data;
+
+ ml->main_loop_quit (ml, g);
+
+ if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
+ error (g, "%s: failed to parse reply header", "guestfs_tgz_out");
+ return;
+ }
+ if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
+ if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
+ error (g, "%s: failed to parse reply error", "guestfs_tgz_out");
+ return;
+ }
+ goto done;
+ }
+ done:
+ ctx->cb_sequence = 1001;
+}
+
+int guestfs_tgz_out (guestfs_h *g,
+ const char *directory,
+ const char *tarball)
+{
+ struct guestfs_tgz_out_args args;
+ struct tgz_out_ctx ctx;
+ guestfs_main_loop *ml = guestfs_get_main_loop (g);
+ int serial;
+
+ if (check_state (g, "guestfs_tgz_out") == -1) return -1;
+ guestfs_set_busy (g);
+
+ memset (&ctx, 0, sizeof ctx);
+
+ args.directory = (char *) directory;
+ serial = guestfs__send_sync (g, GUESTFS_PROC_TGZ_OUT,
+ (xdrproc_t) xdr_guestfs_tgz_out_args, (char *) &args);
+ if (serial == -1) {
+ guestfs_set_ready (g);
+ return -1;
+ }
+
+ guestfs__switch_to_receiving (g);
+ ctx.cb_sequence = 0;
+ guestfs_set_reply_callback (g, tgz_out_reply_cb, &ctx);
+ (void) ml->main_loop_run (ml, g);
+ guestfs_set_reply_callback (g, NULL, NULL);
+ if (ctx.cb_sequence != 1001) {
+ error (g, "%s reply failed, see earlier error messages", "guestfs_tgz_out");
+ guestfs_set_ready (g);
+ return -1;
+ }
+
+ if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_TGZ_OUT, serial) == -1) {
+ guestfs_set_ready (g);
+ return -1;
+ }
+
+ if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
+ error (g, "%s", ctx.err.error_message);
+ guestfs_set_ready (g);
+ return -1;
+ }
+
+ if (guestfs__receive_file_sync (g, tarball) == -1) {
+ guestfs_set_ready (g);
+ return -1;
+ }
+
+ guestfs_set_ready (g);
+ return 0;
+}
+
diff --git a/src/guestfs-actions.h b/src/guestfs-actions.h
index c694ddda..ae54d3a3 100644
--- a/src/guestfs-actions.h
+++ b/src/guestfs-actions.h
@@ -106,3 +106,7 @@ extern int guestfs_blockdev_rereadpt (guestfs_h *handle, const char *device);
extern int guestfs_upload (guestfs_h *handle, const char *filename, const char *remotefilename);
extern int guestfs_download (guestfs_h *handle, const char *remotefilename, const char *filename);
extern char *guestfs_checksum (guestfs_h *handle, const char *csumtype, const char *path);
+extern int guestfs_tar_in (guestfs_h *handle, const char *tarfile, const char *directory);
+extern int guestfs_tar_out (guestfs_h *handle, const char *directory, const char *tarfile);
+extern int guestfs_tgz_in (guestfs_h *handle, const char *tarball, const char *directory);
+extern int guestfs_tgz_out (guestfs_h *handle, const char *directory, const char *tarball);
diff --git a/src/guestfs_protocol.c b/src/guestfs_protocol.c
index fc2eae97..8b88ad95 100644
--- a/src/guestfs_protocol.c
+++ b/src/guestfs_protocol.c
@@ -1229,6 +1229,46 @@ xdr_guestfs_checksum_ret (XDR *xdrs, guestfs_checksum_ret *objp)
}
bool_t
+xdr_guestfs_tar_in_args (XDR *xdrs, guestfs_tar_in_args *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_string (xdrs, &objp->directory, ~0))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_guestfs_tar_out_args (XDR *xdrs, guestfs_tar_out_args *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_string (xdrs, &objp->directory, ~0))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_guestfs_tgz_in_args (XDR *xdrs, guestfs_tgz_in_args *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_string (xdrs, &objp->directory, ~0))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_guestfs_tgz_out_args (XDR *xdrs, guestfs_tgz_out_args *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_string (xdrs, &objp->directory, ~0))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
xdr_guestfs_procedure (XDR *xdrs, guestfs_procedure *objp)
{
register int32_t *buf;
diff --git a/src/guestfs_protocol.h b/src/guestfs_protocol.h
index 05bd40bb..55e6241e 100644
--- a/src/guestfs_protocol.h
+++ b/src/guestfs_protocol.h
@@ -637,6 +637,26 @@ struct guestfs_checksum_ret {
};
typedef struct guestfs_checksum_ret guestfs_checksum_ret;
+struct guestfs_tar_in_args {
+ char *directory;
+};
+typedef struct guestfs_tar_in_args guestfs_tar_in_args;
+
+struct guestfs_tar_out_args {
+ char *directory;
+};
+typedef struct guestfs_tar_out_args guestfs_tar_out_args;
+
+struct guestfs_tgz_in_args {
+ char *directory;
+};
+typedef struct guestfs_tgz_in_args guestfs_tgz_in_args;
+
+struct guestfs_tgz_out_args {
+ char *directory;
+};
+typedef struct guestfs_tgz_out_args guestfs_tgz_out_args;
+
enum guestfs_procedure {
GUESTFS_PROC_MOUNT = 1,
GUESTFS_PROC_SYNC = 2,
@@ -706,7 +726,11 @@ enum guestfs_procedure {
GUESTFS_PROC_UPLOAD = 66,
GUESTFS_PROC_DOWNLOAD = 67,
GUESTFS_PROC_CHECKSUM = 68,
- GUESTFS_PROC_NR_PROCS = 68 + 1,
+ GUESTFS_PROC_TAR_IN = 69,
+ GUESTFS_PROC_TAR_OUT = 70,
+ GUESTFS_PROC_TGZ_IN = 71,
+ GUESTFS_PROC_TGZ_OUT = 72,
+ GUESTFS_PROC_NR_PROCS = 72 + 1,
};
typedef enum guestfs_procedure guestfs_procedure;
#define GUESTFS_MESSAGE_MAX 4194304
@@ -853,6 +877,10 @@ extern bool_t xdr_guestfs_upload_args (XDR *, guestfs_upload_args*);
extern bool_t xdr_guestfs_download_args (XDR *, guestfs_download_args*);
extern bool_t xdr_guestfs_checksum_args (XDR *, guestfs_checksum_args*);
extern bool_t xdr_guestfs_checksum_ret (XDR *, guestfs_checksum_ret*);
+extern bool_t xdr_guestfs_tar_in_args (XDR *, guestfs_tar_in_args*);
+extern bool_t xdr_guestfs_tar_out_args (XDR *, guestfs_tar_out_args*);
+extern bool_t xdr_guestfs_tgz_in_args (XDR *, guestfs_tgz_in_args*);
+extern bool_t xdr_guestfs_tgz_out_args (XDR *, guestfs_tgz_out_args*);
extern bool_t xdr_guestfs_procedure (XDR *, guestfs_procedure*);
extern bool_t xdr_guestfs_message_direction (XDR *, guestfs_message_direction*);
extern bool_t xdr_guestfs_message_status (XDR *, guestfs_message_status*);
@@ -958,6 +986,10 @@ extern bool_t xdr_guestfs_upload_args ();
extern bool_t xdr_guestfs_download_args ();
extern bool_t xdr_guestfs_checksum_args ();
extern bool_t xdr_guestfs_checksum_ret ();
+extern bool_t xdr_guestfs_tar_in_args ();
+extern bool_t xdr_guestfs_tar_out_args ();
+extern bool_t xdr_guestfs_tgz_in_args ();
+extern bool_t xdr_guestfs_tgz_out_args ();
extern bool_t xdr_guestfs_procedure ();
extern bool_t xdr_guestfs_message_direction ();
extern bool_t xdr_guestfs_message_status ();
diff --git a/src/guestfs_protocol.x b/src/guestfs_protocol.x
index ca2d0ced..7f982693 100644
--- a/src/guestfs_protocol.x
+++ b/src/guestfs_protocol.x
@@ -492,6 +492,22 @@ struct guestfs_checksum_ret {
string checksum<>;
};
+struct guestfs_tar_in_args {
+ string directory<>;
+};
+
+struct guestfs_tar_out_args {
+ string directory<>;
+};
+
+struct guestfs_tgz_in_args {
+ string directory<>;
+};
+
+struct guestfs_tgz_out_args {
+ string directory<>;
+};
+
enum guestfs_procedure {
GUESTFS_PROC_MOUNT = 1,
GUESTFS_PROC_SYNC = 2,
@@ -561,6 +577,10 @@ enum guestfs_procedure {
GUESTFS_PROC_UPLOAD = 66,
GUESTFS_PROC_DOWNLOAD = 67,
GUESTFS_PROC_CHECKSUM = 68,
+ GUESTFS_PROC_TAR_IN = 69,
+ GUESTFS_PROC_TAR_OUT = 70,
+ GUESTFS_PROC_TGZ_IN = 71,
+ GUESTFS_PROC_TGZ_OUT = 72,
GUESTFS_PROC_NR_PROCS
};
diff --git a/tests.c b/tests.c
index 876cc29e..1c862691 100644
--- a/tests.c
+++ b/tests.c
@@ -101,6 +101,138 @@ static void no_test_warnings (void)
fprintf (stderr, "warning: \"guestfs_command_lines\" has no tests\n");
fprintf (stderr, "warning: \"guestfs_tune2fs_l\" has no tests\n");
fprintf (stderr, "warning: \"guestfs_blockdev_setbsz\" has no tests\n");
+ fprintf (stderr, "warning: \"guestfs_tar_out\" has no tests\n");
+ fprintf (stderr, "warning: \"guestfs_tgz_out\" has no tests\n");
+}
+
+static int test_tgz_in_0 (void)
+{
+ /* InitBasicFS for tgz_in (0): create ext2 on /dev/sda1 */
+ {
+ int r;
+ suppress_error = 0;
+ r = guestfs_umount_all (g);
+ if (r == -1)
+ return -1;
+ }
+ {
+ int r;
+ suppress_error = 0;
+ r = guestfs_lvm_remove_all (g);
+ if (r == -1)
+ return -1;
+ }
+ {
+ char *lines[] = {
+ ",",
+ NULL
+ };
+ int r;
+ suppress_error = 0;
+ r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines);
+ if (r == -1)
+ return -1;
+ }
+ {
+ int r;
+ suppress_error = 0;
+ r = guestfs_mkfs (g, "ext2", "/dev/sda1");
+ if (r == -1)
+ return -1;
+ }
+ {
+ int r;
+ suppress_error = 0;
+ r = guestfs_mount (g, "/dev/sda1", "/");
+ if (r == -1)
+ return -1;
+ }
+ /* TestOutput for tgz_in (0) */
+ {
+ int r;
+ suppress_error = 0;
+ r = guestfs_tgz_in (g, "images/helloworld.tar.gz", "/");
+ if (r == -1)
+ return -1;
+ }
+ {
+ char *r;
+ suppress_error = 0;
+ r = guestfs_cat (g, "/hello");
+ if (r == NULL)
+ return -1;
+ if (strcmp (r, "hello\n") != 0) {
+ fprintf (stderr, "test_tgz_in_0: expected \"hello\n\" but got \"%s\"\n", r);
+ return -1;
+ }
+ free (r);
+ }
+ return 0;
+}
+
+static int test_tar_in_0 (void)
+{
+ /* InitBasicFS for tar_in (0): create ext2 on /dev/sda1 */
+ {
+ int r;
+ suppress_error = 0;
+ r = guestfs_umount_all (g);
+ if (r == -1)
+ return -1;
+ }
+ {
+ int r;
+ suppress_error = 0;
+ r = guestfs_lvm_remove_all (g);
+ if (r == -1)
+ return -1;
+ }
+ {
+ char *lines[] = {
+ ",",
+ NULL
+ };
+ int r;
+ suppress_error = 0;
+ r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines);
+ if (r == -1)
+ return -1;
+ }
+ {
+ int r;
+ suppress_error = 0;
+ r = guestfs_mkfs (g, "ext2", "/dev/sda1");
+ if (r == -1)
+ return -1;
+ }
+ {
+ int r;
+ suppress_error = 0;
+ r = guestfs_mount (g, "/dev/sda1", "/");
+ if (r == -1)
+ return -1;
+ }
+ /* TestOutput for tar_in (0) */
+ {
+ int r;
+ suppress_error = 0;
+ r = guestfs_tar_in (g, "images/helloworld.tar", "/");
+ if (r == -1)
+ return -1;
+ }
+ {
+ char *r;
+ suppress_error = 0;
+ r = guestfs_cat (g, "/hello");
+ if (r == NULL)
+ return -1;
+ if (strcmp (r, "hello\n") != 0) {
+ fprintf (stderr, "test_tar_in_0: expected \"hello\n\" but got \"%s\"\n", r);
+ return -1;
+ }
+ free (r);
+ }
+ return 0;
}
static int test_checksum_0 (void)
@@ -5048,8 +5180,8 @@ int main (int argc, char *argv[])
char c = 0;
int failed = 0;
const char *srcdir;
+ const char *filename;
int fd;
- char buf[256];
int nr_tests, test_num = 0;
no_test_warnings ();
@@ -5064,89 +5196,90 @@ int main (int argc, char *argv[])
srcdir = getenv ("srcdir");
if (!srcdir) srcdir = ".";
- guestfs_set_path (g, srcdir);
+ chdir (srcdir);
+ guestfs_set_path (g, ".");
- snprintf (buf, sizeof buf, "%s/test1.img", srcdir);
- fd = open (buf, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
+ filename = "test1.img";
+ fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
if (fd == -1) {
- perror (buf);
+ perror (filename);
exit (1);
}
if (lseek (fd, 524288000, SEEK_SET) == -1) {
perror ("lseek");
close (fd);
- unlink (buf);
+ unlink (filename);
exit (1);
}
if (write (fd, &c, 1) == -1) {
perror ("write");
close (fd);
- unlink (buf);
+ unlink (filename);
exit (1);
}
if (close (fd) == -1) {
- perror (buf);
- unlink (buf);
+ perror (filename);
+ unlink (filename);
exit (1);
}
- if (guestfs_add_drive (g, buf) == -1) {
- printf ("guestfs_add_drive %s FAILED\n", buf);
+ if (guestfs_add_drive (g, filename) == -1) {
+ printf ("guestfs_add_drive %s FAILED\n", filename);
exit (1);
}
- snprintf (buf, sizeof buf, "%s/test2.img", srcdir);
- fd = open (buf, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
+ filename = "test2.img";
+ fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
if (fd == -1) {
- perror (buf);
+ perror (filename);
exit (1);
}
if (lseek (fd, 52428800, SEEK_SET) == -1) {
perror ("lseek");
close (fd);
- unlink (buf);
+ unlink (filename);
exit (1);
}
if (write (fd, &c, 1) == -1) {
perror ("write");
close (fd);
- unlink (buf);
+ unlink (filename);
exit (1);
}
if (close (fd) == -1) {
- perror (buf);
- unlink (buf);
+ perror (filename);
+ unlink (filename);
exit (1);
}
- if (guestfs_add_drive (g, buf) == -1) {
- printf ("guestfs_add_drive %s FAILED\n", buf);
+ if (guestfs_add_drive (g, filename) == -1) {
+ printf ("guestfs_add_drive %s FAILED\n", filename);
exit (1);
}
- snprintf (buf, sizeof buf, "%s/test3.img", srcdir);
- fd = open (buf, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
+ filename = "test3.img";
+ fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
if (fd == -1) {
- perror (buf);
+ perror (filename);
exit (1);
}
if (lseek (fd, 10485760, SEEK_SET) == -1) {
perror ("lseek");
close (fd);
- unlink (buf);
+ unlink (filename);
exit (1);
}
if (write (fd, &c, 1) == -1) {
perror ("write");
close (fd);
- unlink (buf);
+ unlink (filename);
exit (1);
}
if (close (fd) == -1) {
- perror (buf);
- unlink (buf);
+ perror (filename);
+ unlink (filename);
exit (1);
}
- if (guestfs_add_drive (g, buf) == -1) {
- printf ("guestfs_add_drive %s FAILED\n", buf);
+ if (guestfs_add_drive (g, filename) == -1) {
+ printf ("guestfs_add_drive %s FAILED\n", filename);
exit (1);
}
@@ -5159,9 +5292,21 @@ int main (int argc, char *argv[])
exit (1);
}
- nr_tests = 73;
+ nr_tests = 75;
test_num++;
+ printf ("%3d/%3d test_tgz_in_0\n", test_num, nr_tests);
+ if (test_tgz_in_0 () == -1) {
+ printf ("test_tgz_in_0 FAILED\n");
+ failed++;
+ }
+ test_num++;
+ printf ("%3d/%3d test_tar_in_0\n", test_num, nr_tests);
+ if (test_tar_in_0 () == -1) {
+ printf ("test_tar_in_0 FAILED\n");
+ failed++;
+ }
+ test_num++;
printf ("%3d/%3d test_checksum_0\n", test_num, nr_tests);
if (test_checksum_0 () == -1) {
printf ("test_checksum_0 FAILED\n");
@@ -5601,12 +5746,9 @@ int main (int argc, char *argv[])
}
guestfs_close (g);
- snprintf (buf, sizeof buf, "%s/test1.img", srcdir);
- unlink (buf);
- snprintf (buf, sizeof buf, "%s/test2.img", srcdir);
- unlink (buf);
- snprintf (buf, sizeof buf, "%s/test3.img", srcdir);
- unlink (buf);
+ unlink ("test1.img");
+ unlink ("test2.img");
+ unlink ("test3.img");
if (failed > 0) {
printf ("***** %d / %d tests FAILED *****\n", failed, nr_tests);