diff options
author | Richard Jones <rjones@redhat.com> | 2009-04-20 15:54:22 +0100 |
---|---|---|
committer | Richard Jones <rjones@redhat.com> | 2009-04-20 15:54:22 +0100 |
commit | 0232e722826cfda0f6042da983f9eb871f24e946 (patch) | |
tree | e08a414ae15cc70f60ed6275231f9ae050a033fe | |
parent | 11350529fee2dbbcfda333bbe10d72f023dc2109 (diff) | |
download | libguestfs-0232e722826cfda0f6042da983f9eb871f24e946.tar.gz libguestfs-0232e722826cfda0f6042da983f9eb871f24e946.tar.xz libguestfs-0232e722826cfda0f6042da983f9eb871f24e946.zip |
Added tar-in, tar-out, tgz-in, tgz-out commands.
-rw-r--r-- | HACKING | 2 | ||||
-rw-r--r-- | daemon/Makefile.am | 1 | ||||
-rw-r--r-- | daemon/actions.h | 4 | ||||
-rw-r--r-- | daemon/stubs.c | 108 | ||||
-rw-r--r-- | daemon/tar.c | 279 | ||||
-rw-r--r-- | fish/cmds.c | 92 | ||||
-rw-r--r-- | fish/completion.c | 4 | ||||
-rw-r--r-- | guestfish-actions.pod | 44 | ||||
-rw-r--r-- | guestfs-actions.pod | 52 | ||||
-rw-r--r-- | images/Makefile.am | 5 | ||||
-rw-r--r-- | images/helloworld.tar | bin | 0 -> 10240 bytes | |||
-rw-r--r-- | images/helloworld.tar.gz | bin | 0 -> 190 bytes | |||
-rw-r--r-- | ocaml/guestfs.ml | 4 | ||||
-rw-r--r-- | ocaml/guestfs.mli | 12 | ||||
-rw-r--r-- | ocaml/guestfs_c_actions.c | 96 | ||||
-rw-r--r-- | perl/Guestfs.xs | 48 | ||||
-rw-r--r-- | perl/lib/Sys/Guestfs.pm | 28 | ||||
-rw-r--r-- | python/guestfs-py.c | 108 | ||||
-rw-r--r-- | python/guestfs.py | 32 | ||||
-rw-r--r-- | ruby/ext/guestfs/_guestfs.c | 108 | ||||
-rwxr-xr-x | src/generator.ml | 108 | ||||
-rw-r--r-- | src/guestfs-actions.c | 360 | ||||
-rw-r--r-- | src/guestfs-actions.h | 4 | ||||
-rw-r--r-- | src/guestfs_protocol.c | 40 | ||||
-rw-r--r-- | src/guestfs_protocol.h | 34 | ||||
-rw-r--r-- | src/guestfs_protocol.x | 20 | ||||
-rw-r--r-- | tests.c | 214 |
27 files changed, 1734 insertions, 73 deletions
@@ -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 Binary files differnew file mode 100644 index 00000000..191a31b2 --- /dev/null +++ b/images/helloworld.tar diff --git a/images/helloworld.tar.gz b/images/helloworld.tar.gz Binary files differnew file mode 100644 index 00000000..9d36cc97 --- /dev/null +++ b/images/helloworld.tar.gz 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 }; @@ -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); |