Richard W.M. Jones
2012-Aug-14 14:51 UTC
[Libguestfs] [PATCH 0/7] Add tar compress, numericowner, excludes flags.
https://bugzilla.redhat.com/show_bug.cgi?id=847880 https://bugzilla.redhat.com/show_bug.cgi?id=847881 This patch series adds various optional arguments to the tar-in and tar-out commands. Firstly (1/7) an optional "compress" flag is added to select compression. This makes the calls tgz-in/tgz-out/txz-in/txz-out deprecated, and expands the range of compression types available. Secondly (2/7) we add an optional numericowner boolean to tar-out, which generates numeric UIDs/GIDs in the resulting tar file. The remaining patches allow us to encode the '--exclude=PATTERN' argument to tar. We add an OStringList type to the generator for passing optional lists of strings. Then we modify tar-out so that this can be translated into zero or more '--exclude' arguments to tar. Note that OStringList is not yet implemented for GObject bindings. Rich.
Richard W.M. Jones
2012-Aug-14 14:51 UTC
[Libguestfs] [PATCH 1/7] Add optional compress flag to tar-in, tar-out APIs.
From: "Richard W.M. Jones" <rjones at redhat.com>
The compress flag can be used to control compression, one of: (none),
"compress", "gzip", "bzip2", "xz",
"lzop". Thus these calls can now
be used instead of tgz-in/tgz-out/txz-in/txz-out, and also support
more compression types.
Mark these APIs as once_had_no_optargs so that compatibility code is
generated.
---
daemon/tar.c | 81 +++++++++++++++++++++++++------------
generator/generator_actions.ml | 49 ++++++++++++++--------
gobject/Makefile.inc | 4 ++
po/POTFILES | 2 +
tests/btrfs/test-btrfs-devices.sh | 8 ++--
tools/virt-tar | 4 +-
6 files changed, 101 insertions(+), 47 deletions(-)
diff --git a/daemon/tar.c b/daemon/tar.c
index 83e68dd..8d78283 100644
--- a/daemon/tar.c
+++ b/daemon/tar.c
@@ -113,9 +113,11 @@ write_cb (void *fd_ptr, const void *buf, size_t len)
}
/* Has one FileIn parameter. */
-static int
-do_tXz_in (const char *dir, const char *filter)
+/* Takes optional arguments, consult optargs_bitmask. */
+int
+do_tar_in (const char *dir, const char *compress)
{
+ const char *filter;
int err, r;
FILE *fp;
char *cmd;
@@ -126,6 +128,24 @@ do_tXz_in (const char *dir, const char *filter)
if (chown_supported == -1)
return -1;
+ if ((optargs_bitmask & GUESTFS_TAR_IN_COMPRESS_BITMASK)) {
+ if (STREQ (compress, "compress"))
+ filter = " --compress";
+ else if (STREQ (compress, "gzip"))
+ filter = " --gzip";
+ else if (STREQ (compress, "bzip2"))
+ filter = " --bzip2";
+ else if (STREQ (compress, "xz"))
+ filter = " --xz";
+ else if (STREQ (compress, "lzop"))
+ filter = " --lzop";
+ else {
+ reply_with_error ("unknown compression type: %s", compress);
+ return -1;
+ }
+ } else
+ filter = "";
+
fd = mkstemp (error_file);
if (fd == -1) {
reply_with_perror ("mkstemp");
@@ -135,7 +155,7 @@ do_tXz_in (const char *dir, const char *filter)
close (fd);
/* "tar -C /sysroot%s -xf -" but we have to quote the dir. */
- if (asprintf_nowarn (&cmd, "tar -C %R -%sxf - %s2> %s",
+ if (asprintf_nowarn (&cmd, "tar -C %R%s -xf - %s2> %s",
dir, filter,
chown_supported ? "" : "--no-same-owner
",
error_file) == -1) {
@@ -203,36 +223,52 @@ do_tXz_in (const char *dir, const char *filter)
/* Has one FileIn parameter. */
int
-do_tar_in (const char *dir)
-{
- return do_tXz_in (dir, "");
-}
-
-/* Has one FileIn parameter. */
-int
do_tgz_in (const char *dir)
{
- return do_tXz_in (dir, "z");
+ optargs_bitmask = GUESTFS_TAR_IN_COMPRESS_BITMASK;
+ return do_tar_in (dir, "gzip");
}
/* Has one FileIn parameter. */
int
do_txz_in (const char *dir)
{
- return do_tXz_in (dir, "J");
+ optargs_bitmask = GUESTFS_TAR_IN_COMPRESS_BITMASK;
+ return do_tar_in (dir, "xz");
}
/* Has one FileOut parameter. */
-static int
-do_tXz_out (const char *dir, const char *filter)
+/* Takes optional arguments, consult optargs_bitmask. */
+int
+do_tar_out (const char *dir, const char *compress)
{
+ const char *filter;
int r;
FILE *fp;
char *cmd;
char buf[GUESTFS_MAX_CHUNK_SIZE];
- /* "tar -C /sysroot%s -zcf - ." but we have to quote the dir. */
- if (asprintf_nowarn (&cmd, "tar -C %R -%scf - .", dir, filter)
== -1) {
+ if ((optargs_bitmask & GUESTFS_TAR_OUT_COMPRESS_BITMASK)) {
+ if (STREQ (compress, "compress"))
+ filter = " --compress";
+ else if (STREQ (compress, "gzip"))
+ filter = " --gzip";
+ else if (STREQ (compress, "bzip2"))
+ filter = " --bzip2";
+ else if (STREQ (compress, "xz"))
+ filter = " --xz";
+ else if (STREQ (compress, "lzop"))
+ filter = " --lzop";
+ else {
+ reply_with_error ("unknown compression type: %s", compress);
+ return -1;
+ }
+ } else
+ filter = "";
+
+ /* "tar -C /sysroot%s -cf - ." but we have to quote the dir. */
+ if (asprintf_nowarn (&cmd, "tar -C %R%s -cf - .",
+ dir, filter) == -1) {
reply_with_perror ("asprintf");
return -1;
}
@@ -282,21 +318,16 @@ do_tXz_out (const char *dir, const char *filter)
/* Has one FileOut parameter. */
int
-do_tar_out (const char *dir)
-{
- return do_tXz_out (dir, "");
-}
-
-/* Has one FileOut parameter. */
-int
do_tgz_out (const char *dir)
{
- return do_tXz_out (dir, "z");
+ optargs_bitmask = GUESTFS_TAR_OUT_COMPRESS_BITMASK;
+ return do_tar_out (dir, "gzip");
}
/* Has one FileOut parameter. */
int
do_txz_out (const char *dir)
{
- return do_tXz_out (dir, "J");
+ optargs_bitmask = GUESTFS_TAR_OUT_COMPRESS_BITMASK;
+ return do_tar_out (dir, "bzip2");
}
diff --git a/generator/generator_actions.ml b/generator/generator_actions.ml
index 3c72e96..a29a685 100644
--- a/generator/generator_actions.ml
+++ b/generator/generator_actions.ml
@@ -3402,40 +3402,58 @@ To get the checksums for many files, use
C<guestfs_checksums_out>." };
{ defaults with
name = "tar_in";
- style = RErr, [FileIn "tarfile"; Pathname "directory"],
[];
+ style = RErr, [FileIn "tarfile"; Pathname "directory"],
[OString "compress"];
proc_nr = Some 69;
+ once_had_no_optargs = true;
cancellable = true;
tests = [
InitScratchFS, Always, TestOutput (
[["mkdir"; "/tar_in"];
- ["tar_in"; "../data/helloworld.tar";
"/tar_in"];
- ["cat"; "/tar_in/hello"]], "hello\n")
+ ["tar_in"; "../data/helloworld.tar";
"/tar_in"; "NOARG"];
+ ["cat"; "/tar_in/hello"]], "hello\n");
+ InitScratchFS, Always, TestOutput (
+ [["mkdir"; "/tar_in_gz"];
+ ["tar_in"; "../data/helloworld.tar.gz";
"/tar_in_gz"; "gzip"];
+ ["cat"; "/tar_in_gz/hello"]],
"hello\n");
+ InitScratchFS, Always, TestOutput (
+ [["mkdir"; "/tar_in_xz"];
+ ["tar_in"; "../data/helloworld.tar.xz";
"/tar_in_xz"; "xz"];
+ ["cat"; "/tar_in_xz/hello"]], "hello\n")
];
shortdesc = "unpack tarfile to directory";
longdesc = "\
-This command uploads and unpacks local file C<tarfile> (an
-I<uncompressed> tar file) into C<directory>.
+This command uploads and unpacks local file C<tarfile> into
C<directory>.
-To upload a compressed tarball, use C<guestfs_tgz_in>
-or C<guestfs_txz_in>." };
+The optional C<compress> flag controls compression. If not given,
+then the input should be an uncompressed tar file. Otherwise one
+of the following strings may be given to select the compression
+type of the input file: C<compress>, C<gzip>, C<bzip2>,
C<xz>, C<lzop>.
+(Note that not all builds of libguestfs will support all of these
+compression types)." };
{ defaults with
name = "tar_out";
- style = RErr, [String "directory"; FileOut "tarfile"],
[];
+ style = RErr, [String "directory"; FileOut "tarfile"],
[OString "compress"];
proc_nr = Some 70;
+ once_had_no_optargs = true;
cancellable = true;
shortdesc = "pack directory into tarfile";
longdesc = "\
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>
-or C<guestfs_txz_out>." };
+The optional C<compress> flag controls compression. If not given,
+then the output will be an uncompressed tar file. Otherwise one
+of the following strings may be given to select the compression
+type of the output file: C<compress>, C<gzip>, C<bzip2>,
C<xz>, C<lzop>.
+(Note that not all builds of libguestfs will support all of these
+compression types)." };
{ defaults with
name = "tgz_in";
style = RErr, [FileIn "tarball"; Pathname "directory"],
[];
proc_nr = Some 71;
+ deprecated_by = Some "tar_in";
cancellable = true;
tests = [
InitScratchFS, Always, TestOutput (
@@ -3446,21 +3464,18 @@ or C<guestfs_txz_out>." };
shortdesc = "unpack compressed tarball to directory";
longdesc = "\
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>." };
+I<gzip compressed> tar file) into C<directory>." };
{ defaults with
name = "tgz_out";
style = RErr, [Pathname "directory"; FileOut
"tarball"], [];
proc_nr = Some 72;
+ deprecated_by = Some "tar_out";
cancellable = true;
shortdesc = "pack directory into compressed tarball";
longdesc = "\
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>." };
+it to local file C<tarball>." };
{ defaults with
name = "mount_ro";
@@ -6764,6 +6779,7 @@ or growing unnecessarily." };
name = "txz_in";
style = RErr, [FileIn "tarball"; Pathname "directory"],
[];
proc_nr = Some 229;
+ deprecated_by = Some "tar_in";
optional = Some "xz"; cancellable = true;
tests = [
InitScratchFS, Always, TestOutput (
@@ -6780,6 +6796,7 @@ I<xz compressed> tar file) into
C<directory>." };
name = "txz_out";
style = RErr, [Pathname "directory"; FileOut
"tarball"], [];
proc_nr = Some 230;
+ deprecated_by = Some "tar_out";
optional = Some "xz"; cancellable = true;
shortdesc = "pack directory into compressed tarball";
longdesc = "\
diff --git a/gobject/Makefile.inc b/gobject/Makefile.inc
index 8c4b2d1..49f9538 100644
--- a/gobject/Makefile.inc
+++ b/gobject/Makefile.inc
@@ -47,6 +47,8 @@ guestfs_gobject_headers= \
include/guestfs-gobject/optargs-mount_local.h \
include/guestfs-gobject/optargs-umount_local.h \
include/guestfs-gobject/optargs-umount.h \
+ include/guestfs-gobject/optargs-tar_in.h \
+ include/guestfs-gobject/optargs-tar_out.h \
include/guestfs-gobject/optargs-grep.h \
include/guestfs-gobject/optargs-mkfs.h \
include/guestfs-gobject/optargs-mount_9p.h \
@@ -99,6 +101,8 @@ guestfs_gobject_sources= \
src/optargs-mount_local.c \
src/optargs-umount_local.c \
src/optargs-umount.c \
+ src/optargs-tar_in.c \
+ src/optargs-tar_out.c \
src/optargs-grep.c \
src/optargs-mkfs.c \
src/optargs-mount_9p.c \
diff --git a/po/POTFILES b/po/POTFILES
index d1fcc4d..08d2ab8 100644
--- a/po/POTFILES
+++ b/po/POTFILES
@@ -162,6 +162,8 @@ gobject/src/optargs-rsync.c
gobject/src/optargs-rsync_in.c
gobject/src/optargs-rsync_out.c
gobject/src/optargs-set_e2attrs.c
+gobject/src/optargs-tar_in.c
+gobject/src/optargs-tar_out.c
gobject/src/optargs-tune2fs.c
gobject/src/optargs-umount.c
gobject/src/optargs-umount_local.c
diff --git a/tests/btrfs/test-btrfs-devices.sh
b/tests/btrfs/test-btrfs-devices.sh
index d2de6f6..d1f1ce7 100755
--- a/tests/btrfs/test-btrfs-devices.sh
+++ b/tests/btrfs/test-btrfs-devices.sh
@@ -51,7 +51,7 @@ mkfs-btrfs "/dev/sda1 /dev/sdb1"
mount /dev/sda1 /
mkdir /data1
-txz-in ../data/filesanddirs-10M.tar.xz /data1
+tar-in ../data/filesanddirs-10M.tar.xz /data1 compress:xz
# In btrfs-progs 0.19, a test was added which prevents us from
# deleting the mount device (/dev/sda1) although that restriction
@@ -64,7 +64,7 @@ btrfs-device-add "/dev/sdb1" /
btrfs-device-delete "/dev/sdc1 /dev/sdd1" /
mkdir /data2
-txz-in ../data/filesanddirs-10M.tar.xz /data2
+tar-in ../data/filesanddirs-10M.tar.xz /data2 compress:xz
btrfs-device-add "/dev/sdc1 /dev/sdd1" /
btrfs-device-delete "/dev/sdb1" /
@@ -72,7 +72,7 @@ btrfs-device-add "/dev/sdb1" /
btrfs-device-delete "/dev/sdc1 /dev/sdd1" /
mkdir /data3
-txz-in ../data/filesanddirs-10M.tar.xz /data3
+tar-in ../data/filesanddirs-10M.tar.xz /data3 compress:xz
btrfs-device-add "/dev/sdc1 /dev/sdd1" /
btrfs-device-delete "/dev/sdb1" /
@@ -80,7 +80,7 @@ btrfs-device-add "/dev/sdb1" /
btrfs-device-delete "/dev/sdc1 /dev/sdd1" /
mkdir /data4
-txz-in ../data/filesanddirs-10M.tar.xz /data4
+tar-in ../data/filesanddirs-10M.tar.xz /data4 compress:xz
btrfs-device-add "/dev/sdc1 /dev/sdd1" /
btrfs-device-delete "/dev/sdb1" /
diff --git a/tools/virt-tar b/tools/virt-tar
index 801104f..053231c 100755
--- a/tools/virt-tar
+++ b/tools/virt-tar
@@ -267,13 +267,13 @@ foreach (@fses) {
# Do the tar command.
if ($mode eq "x") {
if ($gzip) {
- $g->tgz_out ($directory, $tarball);
+ $g->tar_out ($directory, $tarball, compress => "gzip");
} else {
$g->tar_out ($directory, $tarball);
}
} else { # mode eq "u"
if ($gzip) {
- $g->tgz_in ($tarball, $directory);
+ $g->tar_in ($tarball, $directory, compress => "gzip");
} else {
$g->tar_in ($tarball, $directory);
}
--
1.7.10.4
Richard W.M. Jones
2012-Aug-14 14:51 UTC
[Libguestfs] [PATCH 2/7] tar-out: Add optional numericowner flag (RHBZ#847880).
From: "Richard W.M. Jones" <rjones at redhat.com>
This is equivalent to the tar option --numeric-owner.
---
daemon/tar.c | 14 +++++++++-----
generator/generator_actions.ml | 15 +++++++++++++--
2 files changed, 22 insertions(+), 7 deletions(-)
diff --git a/daemon/tar.c b/daemon/tar.c
index 8d78283..f46733d 100644
--- a/daemon/tar.c
+++ b/daemon/tar.c
@@ -240,7 +240,7 @@ do_txz_in (const char *dir)
/* Has one FileOut parameter. */
/* Takes optional arguments, consult optargs_bitmask. */
int
-do_tar_out (const char *dir, const char *compress)
+do_tar_out (const char *dir, const char *compress, int numericowner)
{
const char *filter;
int r;
@@ -266,9 +266,13 @@ do_tar_out (const char *dir, const char *compress)
} else
filter = "";
+ if (!(optargs_bitmask & GUESTFS_TAR_OUT_NUMERICOWNER_BITMASK))
+ numericowner = 0;
+
/* "tar -C /sysroot%s -cf - ." but we have to quote the dir. */
- if (asprintf_nowarn (&cmd, "tar -C %R%s -cf - .",
- dir, filter) == -1) {
+ if (asprintf_nowarn (&cmd, "tar -C %R%s%s -cf - .",
+ dir, filter,
+ numericowner ? " --numeric-owner" :
"") == -1) {
reply_with_perror ("asprintf");
return -1;
}
@@ -321,7 +325,7 @@ int
do_tgz_out (const char *dir)
{
optargs_bitmask = GUESTFS_TAR_OUT_COMPRESS_BITMASK;
- return do_tar_out (dir, "gzip");
+ return do_tar_out (dir, "gzip", 0);
}
/* Has one FileOut parameter. */
@@ -329,5 +333,5 @@ int
do_txz_out (const char *dir)
{
optargs_bitmask = GUESTFS_TAR_OUT_COMPRESS_BITMASK;
- return do_tar_out (dir, "bzip2");
+ return do_tar_out (dir, "bzip2", 0);
}
diff --git a/generator/generator_actions.ml b/generator/generator_actions.ml
index a29a685..0771b62 100644
--- a/generator/generator_actions.ml
+++ b/generator/generator_actions.ml
@@ -3433,7 +3433,7 @@ compression types)." };
{ defaults with
name = "tar_out";
- style = RErr, [String "directory"; FileOut "tarfile"],
[OString "compress"];
+ style = RErr, [String "directory"; FileOut "tarfile"],
[OString "compress"; OBool "numericowner"];
proc_nr = Some 70;
once_had_no_optargs = true;
cancellable = true;
@@ -3447,7 +3447,18 @@ then the output will be an uncompressed tar file.
Otherwise one
of the following strings may be given to select the compression
type of the output file: C<compress>, C<gzip>, C<bzip2>,
C<xz>, C<lzop>.
(Note that not all builds of libguestfs will support all of these
-compression types)." };
+compression types).
+
+The other optional arguments are:
+
+=over 4
+
+=item C<numericowner>
+
+If set to true, the output tar file will contain UID/GID numbers
+instead of user/group names.
+
+=back" };
{ defaults with
name = "tgz_in";
--
1.7.10.4
Richard W.M. Jones
2012-Aug-14 14:51 UTC
[Libguestfs] [PATCH 3/7] todo: Suggestion: Add sh-in, sh-out, debug sh-in, debug sh-out.
From: "Richard W.M. Jones" <rjones at redhat.com>
---
TODO | 3 +++
1 file changed, 3 insertions(+)
diff --git a/TODO b/TODO
index f09d389..efc0b04 100644
--- a/TODO
+++ b/TODO
@@ -68,6 +68,9 @@ Ideas for extra commands
pivot_root
fts(3) / ftw(3)
+ sh-in, sh-out: run shell command with large input/output
+ debug sh-in, debug sh-out: debug versions of the above
+
Other initrd-* commands
-----------------------
--
1.7.10.4
Richard W.M. Jones
2012-Aug-14 14:51 UTC
[Libguestfs] [PATCH 4/7] bindtests: Space before parens in call.
From: "Richard W.M. Jones" <rjones at redhat.com>
---
generator/generator_bindtests.ml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/generator/generator_bindtests.ml b/generator/generator_bindtests.ml
index 6bb86f8..044c57d 100644
--- a/generator/generator_bindtests.ml
+++ b/generator/generator_bindtests.ml
@@ -97,7 +97,7 @@ print_strings (char *const *argv)
pr " printf (\"%s: \");\n" n;
pr " if (optargs->bitmask &
GUESTFS_INTERNAL_TEST_%s_BITMASK) {\n"
(String.uppercase n);
- pr " printf(%s);\n" printf_args;
+ pr " printf (%s);\n" printf_args;
pr " } else {\n";
pr " printf (\"unset\\n\");\n";
pr " }\n";
--
1.7.10.4
Richard W.M. Jones
2012-Aug-14 14:51 UTC
[Libguestfs] [PATCH 5/7] daemon: New utility functions 'join_strings', 'concat_strings'.
From: "Richard W.M. Jones" <rjones at redhat.com>
Useful functions for concatenating strings together.
---
daemon/daemon.h | 7 +++++++
daemon/guestfsd.c | 41 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 48 insertions(+)
diff --git a/daemon/daemon.h b/daemon/daemon.h
index 85eec45..b9dba13 100644
--- a/daemon/daemon.h
+++ b/daemon/daemon.h
@@ -82,6 +82,13 @@ extern void free_stringslen (char **argv, size_t len);
extern void sort_device_names (char **argv, size_t len);
extern int compare_device_names (const char *a, const char *b);
+/* Concatenate strings, optionally with a separator string between
+ * each. On error, these return NULL but do NOT call reply_with_* nor
+ * free anything.
+ */
+extern char *concat_strings (const struct stringsbuf *sb);
+extern char *join_strings (const char *separator, const struct stringsbuf *sb);
+
extern char **split_lines (char *str);
#define command(out,err,name,...) commandf((out),(err),0,(name),__VA_ARGS__)
diff --git a/daemon/guestfsd.c b/daemon/guestfsd.c
index 2b0acf9..17a0aa0 100644
--- a/daemon/guestfsd.c
+++ b/daemon/guestfsd.c
@@ -578,6 +578,47 @@ sort_device_names (char **argv, size_t len)
qsort (argv, len, sizeof (char *), compare_device_names_vp);
}
+char *
+concat_strings (const struct stringsbuf *sb)
+{
+ return join_strings ("", sb);
+}
+
+char *
+join_strings (const char *separator, const struct stringsbuf *sb)
+{
+ size_t i, len, seplen, rlen;
+ char *r;
+
+ seplen = strlen (separator);
+
+ len = 0;
+ for (i = 0; i < sb->size; ++i) {
+ if (i > 0)
+ len += seplen;
+ len += strlen (sb->argv[i]);
+ }
+ len++; /* for final \0 */
+
+ r = malloc (len);
+ if (r == NULL)
+ return NULL;
+
+ rlen = 0;
+ for (i = 0; i < sb->size; ++i) {
+ if (i > 0) {
+ memcpy (&r[rlen], separator, seplen);
+ rlen += seplen;
+ }
+ len = strlen (sb->argv[i]);
+ memcpy (&r[rlen], sb->argv[i], len);
+ rlen += len;
+ }
+ r[rlen] = '\0';
+
+ return r;
+}
+
/* Easy ways to run external commands. For full documentation, see
* 'commandrvf' below.
*/
--
1.7.10.4
Richard W.M. Jones
2012-Aug-14 14:51 UTC
[Libguestfs] [PATCH 6/7] generator: Add new OStringList optional arg type.
From: "Richard W.M. Jones" <rjones at redhat.com>
This allows lists of strings to be passed as an optional argument.
---
bindtests | 69 ++++++++++++++++++++++++++++++++++++
generator/generator_actions.ml | 9 ++---
generator/generator_bindtests.ml | 55 ++++++++++++++++++++++++++++
generator/generator_c.ml | 52 ++++++++++++++++++++++-----
generator/generator_erlang.ml | 6 ++++
generator/generator_fish.ml | 17 ++++++---
generator/generator_gobject.ml | 47 ++++++++++++++----------
generator/generator_java.ml | 44 +++++++++++++++++++----
generator/generator_ocaml.ml | 6 ++++
generator/generator_perl.ml | 27 +++++++++++---
generator/generator_php.ml | 56 ++++++++++++++++++++++++-----
generator/generator_python.ml | 37 ++++++++++++++-----
generator/generator_ruby.ml | 15 ++++++++
generator/generator_tests_c_api.ml | 17 ++++++++-
generator/generator_types.ml | 3 ++
generator/generator_utils.ml | 3 +-
gobject/run-tests | 10 +++++-
17 files changed, 407 insertions(+), 66 deletions(-)
diff --git a/bindtests b/bindtests
index c42feda..a86162c 100644
--- a/bindtests
+++ b/bindtests
@@ -11,6 +11,7 @@ obool: true
oint: 1
oint64: unset
ostring: unset
+ostringlist: unset
abc
null
[]
@@ -24,6 +25,7 @@ obool: unset
oint: unset
oint64: 1
ostring: string
+ostringlist: unset
def
[]
@@ -37,6 +39,7 @@ obool: false
oint: unset
oint64: unset
ostring: unset
+ostringlist: unset
[]
@@ -50,6 +53,7 @@ obool: unset
oint: unset
oint64: unset
ostring: unset
+ostringlist: unset
abc
def
["1"]
@@ -63,6 +67,7 @@ obool: unset
oint: unset
oint64: unset
ostring: unset
+ostringlist: unset
abc
def
["1", "2"]
@@ -76,6 +81,7 @@ obool: unset
oint: unset
oint64: unset
ostring: unset
+ostringlist: unset
abc
def
["1"]
@@ -89,6 +95,7 @@ obool: unset
oint: unset
oint64: unset
ostring: unset
+ostringlist: unset
abc
def
["1"]
@@ -102,6 +109,7 @@ obool: unset
oint: unset
oint64: unset
ostring: unset
+ostringlist: unset
abc
def
["1"]
@@ -115,6 +123,7 @@ obool: unset
oint: unset
oint64: unset
ostring: unset
+ostringlist: unset
abc
def
["1"]
@@ -128,6 +137,7 @@ obool: unset
oint: unset
oint64: unset
ostring: unset
+ostringlist: unset
abc
def
["1"]
@@ -141,6 +151,7 @@ obool: unset
oint: unset
oint64: unset
ostring: unset
+ostringlist: unset
abc
def
["1"]
@@ -154,6 +165,7 @@ obool: unset
oint: unset
oint64: unset
ostring: unset
+ostringlist: unset
abc
def
["1"]
@@ -167,4 +179,61 @@ obool: unset
oint: unset
oint64: unset
ostring: unset
+ostringlist: unset
+abc
+def
+[]
+false
+0
+0
+123
+456
+<61><62><63><00><61><62><63>
+obool: unset
+oint: unset
+oint64: unset
+ostring: unset
+ostringlist: []
+abc
+def
+[]
+false
+0
+0
+123
+456
+<61><62><63><00><61><62><63>
+obool: unset
+oint: unset
+oint64: unset
+ostring: unset
+ostringlist: ["optelem1"]
+abc
+def
+[]
+false
+0
+0
+123
+456
+<61><62><63><00><61><62><63>
+obool: unset
+oint: unset
+oint64: unset
+ostring: unset
+ostringlist: ["optelem1", "optelem2"]
+abc
+def
+[]
+false
+0
+0
+123
+456
+<61><62><63><00><61><62><63>
+obool: unset
+oint: unset
+oint64: unset
+ostring: unset
+ostringlist: ["optelem1", "optelem2", "optelem3"]
EOF
diff --git a/generator/generator_actions.ml b/generator/generator_actions.ml
index 0771b62..19c81be 100644
--- a/generator/generator_actions.ml
+++ b/generator/generator_actions.ml
@@ -50,10 +50,11 @@ let test_all_args = [
]
let test_all_optargs = [
- OBool "obool";
- OInt "oint";
- OInt64 "oint64";
- OString "ostring"
+ OBool "obool";
+ OInt "oint";
+ OInt64 "oint64";
+ OString "ostring";
+ OStringList "ostringlist";
]
let test_all_rets = [
diff --git a/generator/generator_bindtests.ml b/generator/generator_bindtests.ml
index 044c57d..67a5bba 100644
--- a/generator/generator_bindtests.ml
+++ b/generator/generator_bindtests.ml
@@ -117,6 +117,14 @@ print_strings (char *const *argv)
| OString n ->
let printf_args = sprintf "\"%%s\\n\",
optargs->%s" n in
check_optarg n printf_args;
+ | OStringList n ->
+ pr " printf (\"%s: \");\n" n;
+ pr " if (optargs->bitmask &
GUESTFS_INTERNAL_TEST_%s_BITMASK) {\n"
+ (String.uppercase n);
+ pr " print_strings (optargs->%s);\n" n;
+ pr " } else {\n";
+ pr " printf (\"unset\\n\");\n";
+ pr " }\n";
) optargs;
pr " /* Java changes stdout line buffering so we need this:
*/\n";
pr " fflush (stdout);\n";
@@ -270,6 +278,9 @@ let () | CallOInt (n, v) -> "~" ^
n ^ ":" ^ string_of_int v
| CallOInt64 (n, v) -> "~" ^ n ^ ":" ^
Int64.to_string v ^ "L"
| CallOString (n, v) -> "~" ^ n ^ ":\"" ^
v ^ "\""
+ | CallOStringList (n, xs) ->
+ "~" ^ n ^ ":" ^
+ "[|" ^ String.concat ";" (List.map (sprintf
"\"%s\"") xs) ^ "|]"
) optargs
)
in
@@ -318,6 +329,9 @@ my $g = Sys::Guestfs->new ();
| CallOInt (n, v) -> "'" ^ n ^ "' =>
" ^ string_of_int v
| CallOInt64 (n, v) -> "'" ^ n ^ "' =>
" ^ Int64.to_string v
| CallOString (n, v) -> "'" ^ n ^ "' =>
'" ^ v ^ "'"
+ | CallOStringList (n, xs) ->
+ "'" ^ n ^ "' => " ^
+ "[" ^ String.concat "," (List.map (sprintf
"\"%s\"") xs) ^ "]"
) optargs
)
in
@@ -363,6 +377,9 @@ g = guestfs.GuestFS ()
| CallOInt (n, v) -> n ^ "=" ^ string_of_int v
| CallOInt64 (n, v) -> n ^ "=" ^ Int64.to_string v
| CallOString (n, v) -> n ^ "=\"" ^ v ^
"\""
+ | CallOStringList (n, xs) ->
+ n ^ "=" ^
+ "[" ^ String.concat "," (List.map (sprintf
"\"%s\"") xs) ^ "]"
) optargs
)
in
@@ -410,6 +427,9 @@ g = Guestfs::create()
| CallOInt (n, v) -> ":" ^ n ^ " => " ^
string_of_int v
| CallOInt64 (n, v) -> ":" ^ n ^ " => " ^
Int64.to_string v
| CallOString (n, v) -> ":" ^ n ^ " =>
\"" ^ v ^ "\""
+ | CallOStringList (n, xs) ->
+ ":" ^ n ^ " => " ^
+ "[" ^ String.concat "," (List.map (sprintf
"\"%s\"") xs) ^ "]"
) optargs
) ^
"}"
@@ -453,6 +473,11 @@ public class Bindtests {
" put(\"" ^ n ^ "\", " ^
Int64.to_string v ^ "l);"
| CallOString (n, v) ->
" put(\"" ^ n ^ "\", \"" ^ v ^
"\");"
+ | CallOStringList (n, xs) ->
+ " put(\"" ^ n ^ "\", " ^
+ "new String[]{" ^
+ String.concat "," (List.map (sprintf
"\"%s\"") xs) ^
+ "});"
) optargs @
[ "}};\n" ]
| None ->
@@ -560,6 +585,12 @@ var o;
| CallOInt (n, v) -> n ^ ": " ^ (string_of_int v)
| CallOInt64 (n, v) -> n ^ ": " ^ Int64.to_string v
| CallOString (n, v) -> n ^ ": \"" ^ v ^
"\""
+ | CallOStringList (n, xs) -> "" (* not implemented XXX
*)
+(*
+ | CallOStringList (n, xs) ->
+ n ^ ": " ^
+ "[" ^ String.concat "," (List.map (sprintf
"\"%s\"") xs) ^ "]"
+*)
) optargs
)
) ^
@@ -667,5 +698,29 @@ and generate_lang_bindtests call CallStringList
["1"]; CallBool false;
CallInt 0; CallInt64 0L; CallString ""; CallString "";
CallBuffer "abc\000abc"] None;
+ call "internal_test"
+ [CallString "abc"; CallOptString (Some "def");
+ CallStringList []; CallBool false;
+ CallInt 0; CallInt64 0L; CallString "123"; CallString
"456";
+ CallBuffer "abc\000abc"]
+ (Some [CallOStringList ("ostringlist", [])]);
+ call "internal_test"
+ [CallString "abc"; CallOptString (Some "def");
+ CallStringList []; CallBool false;
+ CallInt 0; CallInt64 0L; CallString "123"; CallString
"456";
+ CallBuffer "abc\000abc"]
+ (Some [CallOStringList ("ostringlist", ["optelem1"])]);
+ call "internal_test"
+ [CallString "abc"; CallOptString (Some "def");
+ CallStringList []; CallBool false;
+ CallInt 0; CallInt64 0L; CallString "123"; CallString
"456";
+ CallBuffer "abc\000abc"]
+ (Some [CallOStringList ("ostringlist", ["optelem1";
"optelem2"])]);
+ call "internal_test"
+ [CallString "abc"; CallOptString (Some "def");
+ CallStringList []; CallBool false;
+ CallInt 0; CallInt64 0L; CallString "123"; CallString
"456";
+ CallBuffer "abc\000abc"]
+ (Some [CallOStringList ("ostringlist", ["optelem1";
"optelem2"; "optelem3"])]);
(* XXX Add here tests of the return and error functions. *)
diff --git a/generator/generator_c.ml b/generator/generator_c.ml
index ebd252f..e150441 100644
--- a/generator/generator_c.ml
+++ b/generator/generator_c.ml
@@ -210,6 +210,7 @@ and generate_actions_pod_entry ({ c_name = c_name;
| OInt n -> pr "int %s,\n" n
| OInt64 n -> pr "int64_t %s,\n" n
| OString n -> pr "const char *%s,\n" n
+ | OStringList n -> pr "char *const *%s,\n" n
) optargs;
pr "\n";
);
@@ -614,7 +615,8 @@ extern GUESTFS_DLL_PUBLIC void *guestfs_next_private
(guestfs_h *g, const char *
| OBool n -> "int "
| OInt n -> "int "
| OInt64 n -> "int64_t "
- | OString n -> "const char *" in
+ | OString n -> "const char *"
+ | OStringList n -> "char *const *" in
let uc_shortname = String.uppercase shortname in
let n = name_of_optargt argt in
let uc_n = String.uppercase n in
@@ -862,6 +864,20 @@ trace_send_line (guestfs_h *g)
pr " }\n";
pr_newline := true
+ | OStringList n ->
+ pr " if ((optargs->bitmask & GUESTFS_%s_%s_BITMASK)
&&\n"
+ (String.uppercase c_name) (String.uppercase n);
+ pr " optargs->%s == NULL) {\n" n;
+ pr " error (g, \"%%s: %%s: optional list cannot be
NULL\",\n";
+ pr " \"%s\", \"%s\");\n"
c_name n;
+ let errcode + match errcode_of_ret ret with
+ | `CannotReturnError -> assert false
+ | (`ErrorIsMinusOne |`ErrorIsNULL) as e -> e in
+ pr " return %s;\n" (string_of_errcode errcode);
+ pr " }\n";
+ pr_newline := true
+
(* not applicable *)
| OBool _ | OInt _ | OInt64 _ -> ()
) optargs;
@@ -893,8 +909,11 @@ trace_send_line (guestfs_h *g)
let needs_i List.exists (function
- | StringList _ | DeviceList _ -> true
- | _ -> false) args in
+ | StringList _ | DeviceList _ -> true
+ | _ -> false) args ||
+ List.exists (function
+ | OStringList _ -> true
+ | _ -> false) optargs in
if needs_i then (
pr " size_t i;\n";
pr "\n"
@@ -952,6 +971,13 @@ trace_send_line (guestfs_h *g)
(match argt with
| OString n ->
pr " fprintf (trace_fp, \"
\\\"%%s:%%s\\\"\", \"%s\", optargs->%s);\n" n n
+ | OStringList n ->
+ pr " fprintf (trace_fp, \" \\\"%%s:\",
\"%s\");\n" n;
+ pr " for (i = 0; optargs->%s[i] != NULL; ++i)
{\n" n;
+ pr " if (i > 0) fputc (' ',
trace_fp);\n";
+ pr " fputs (optargs->%s[i], trace_fp);\n" n;
+ pr " }\n";
+ pr " fputc ('\\\"', trace_fp);\n"
| OBool n ->
pr " fprintf (trace_fp, \"
\\\"%%s:%%s\\\"\", \"%s\", optargs->%s ?
\"true\" : \"false\");\n" n n
| OInt n ->
@@ -1239,19 +1265,28 @@ trace_send_line (guestfs_h *g)
List.iter (
fun argt ->
let n = name_of_optargt argt in
- pr " if (optargs->bitmask &
GUESTFS_%s_%s_BITMASK)\n"
+ pr " if (optargs->bitmask & GUESTFS_%s_%s_BITMASK)
{\n"
(String.uppercase c_name) (String.uppercase n);
(match argt with
| OBool n
| OInt n
| OInt64 n ->
pr " args.%s = optargs->%s;\n" n n;
- pr " else\n";
- pr " args.%s = 0;\n" n
+ pr " } else {\n";
+ pr " args.%s = 0;\n" n;
+ pr " }\n";
| OString n ->
pr " args.%s = (char *) optargs->%s;\n" n n;
- pr " else\n";
- pr " args.%s = (char *) \"\";\n" n
+ pr " } else {\n";
+ pr " args.%s = (char *) \"\";\n" n;
+ pr " }\n";
+ | OStringList n ->
+ pr " args.%s.%s_val = (char **) optargs->%s;\n" n n
n;
+ pr " for (args.%s.%s_len = 0;
optargs->%s[args.%s.%s_len]; args.%s.%s_len++) ;\n" n n n n n n n;
+ pr " } else {\n";
+ pr " args.%s.%s_len = 0;\n" n n;
+ pr " args.%s.%s_val = NULL;\n" n n;
+ pr " }\n";
)
) optargs;
@@ -1489,6 +1524,7 @@ trace_send_line (guestfs_h *g)
| OBool _ | OInt _ -> pr "int"
| OInt64 _ -> pr "int64_t"
| OString _ -> pr "const char *"
+ | OStringList _ -> pr "char *const *"
);
pr ");\n";
pr " break;\n";
diff --git a/generator/generator_erlang.ml b/generator/generator_erlang.ml
index 3c2c04d..a11c71c 100644
--- a/generator/generator_erlang.ml
+++ b/generator/generator_erlang.ml
@@ -338,6 +338,7 @@ extern void free_strings (char **r);
| OInt _ -> pr "ERL_INT_VALUE (hd_value)"
| OInt64 _ -> pr "ERL_LL_VALUE (hd_value)"
| OString _ -> pr "erl_iolist_to_string (hd_value)"
+ | OStringList n -> pr "get_string_list (hd_value)"
);
pr ";\n";
pr " }\n";
@@ -393,6 +394,11 @@ extern void free_strings (char **r);
pr " if ((optargs_s.bitmask & %s_%s_BITMASK))\n"
c_optarg_prefix uc_n;
pr " free ((char *) optargs_s.%s);\n" n
+ | OStringList n ->
+ let uc_n = String.uppercase n in
+ pr " if ((optargs_s.bitmask & %s_%s_BITMASK))\n"
+ c_optarg_prefix uc_n;
+ pr " free_strings ((char **) optargs_s.%s);\n" n
) optargs;
(match errcode_of_ret ret with
diff --git a/generator/generator_fish.ml b/generator/generator_fish.ml
index a85d53d..d0c7e3d 100644
--- a/generator/generator_fish.ml
+++ b/generator/generator_fish.ml
@@ -35,7 +35,8 @@ let doc_opttype_of = function
| OBool n -> "true|false"
| OInt n
| OInt64 n -> "N"
- | OString n -> ".."
+ | OString n
+ | OStringList n -> ".."
let get_aliases { fish_alias = fish_alias; non_c_aliases = non_c_aliases }
let non_c_aliases @@ -494,6 +495,9 @@ Guestfish will prompt for these
separately."
(sprintf "optargs_s.%s" n) "out"
| OString n ->
pr " optargs_s.%s = &argv[i][%d];\n" n
(len+1);
+ | OStringList name ->
+ pr " optargs_s.%s = parse_string_list
(&argv[i][%d]);\n" name (len+1);
+ pr " if (optargs_s.%s == NULL) goto out_%s;\n"
name name
);
pr " this_mask = %s_%s_BITMASK;\n" c_optarg_prefix
uc_n;
pr " this_arg = \"%s\";\n" n;
@@ -602,6 +606,13 @@ Guestfish will prompt for these separately."
| _ -> pr " out:\n");
List.iter (
function
+ | OStringList name ->
+ pr " free_strings ((char **) optargs_s.%s);\n" name;
+ pr " out_%s:\n" name
+ | OBool _ | OInt _ | OInt64 _ | OString _ -> ()
+ ) (List.rev optargs);
+ List.iter (
+ function
| Device _ | String _
| OptString _ | Bool _
| BufferIn _ -> ()
@@ -857,9 +868,7 @@ and generate_fish_actions_pod () | Pointer _ ->
assert false
) args;
List.iter (
- function
- | (OBool n | OInt n | OInt64 n | OString n) as arg ->
- pr " [%s:%s]" n (doc_opttype_of arg)
+ fun arg -> pr " [%s:%s]" (name_of_optargt arg)
(doc_opttype_of arg)
) optargs;
pr "\n";
pr "\n";
diff --git a/generator/generator_gobject.ml b/generator/generator_gobject.ml
index 45bcaa4..f117823 100644
--- a/generator/generator_gobject.ml
+++ b/generator/generator_gobject.ml
@@ -18,6 +18,8 @@
(* Please read generator/README first. *)
+(* NB: This is missing support for OStringList. *)
+
open Printf
open Generator_actions
@@ -371,14 +373,12 @@ let generate_gobject_optargs_source name optargs f ()
pr "struct _%sPrivate {\n" camel_name;
List.iter (
- fun optargt ->
- let name = name_of_optargt optargt in
- let typ = match optargt with
- | OBool n -> "GuestfsTristate "
- | OInt n -> "gint "
- | OInt64 n -> "gint64 "
- | OString n -> "gchar *" in
- pr " %s%s;\n" typ name;
+ function
+ | OBool n -> pr " GuestfsTristate %s;\n" n
+ | OInt n -> pr " gint %s;\n" n
+ | OInt64 n -> pr " gint64 %s;\n" n
+ | OString n -> pr " gchar *%s;\n" n
+ | OStringList _ -> pr " /* OStringList not implemented yet
*/\n"
) optargs;
pr "};\n\n";
@@ -401,21 +401,23 @@ let generate_gobject_optargs_source name optargs f ()
pr " switch (property_id) {\n";
List.iter (
- fun optargt ->
+ function OStringList _ -> () (* XXX *)
+ | optargt ->
let optname = name_of_optargt optargt in
let uc_optname = String.uppercase optname in
pr " case PROP_GUESTFS_%s_%s:\n" uc_name uc_optname;
(match optargt with
| OString n ->
pr " g_free(priv->%s);\n" n;
- | OBool _ | OInt _ | OInt64 _ -> ());
- let set_value_func = match optargt with
- | OBool _ -> "g_value_get_enum"
- | OInt _ -> "g_value_get_int"
- | OInt64 _ -> "g_value_get_int64"
- | OString _ -> "g_value_dup_string"
- in
- pr " priv->%s = %s(value);\n" optname set_value_func;
+ | OBool _ | OInt _ | OInt64 _ -> ()
+ | OStringList _ -> () (* XXX *));
+ (match optargt with
+ | OBool n -> pr " priv->%s = g_value_get_enum
(value);\n" n
+ | OInt n -> pr " priv->%s = g_value_get_int
(value);\n" n
+ | OInt64 n -> pr " priv->%s = g_value_get_int64
(value);\n" n
+ | OString n -> pr " priv->%s = g_value_dup_string
(value);\n" n
+ | OStringList _ -> ()
+ );
pr " break;\n\n";
) optargs;
pr " default:\n";
@@ -432,7 +434,8 @@ let generate_gobject_optargs_source name optargs f ()
pr " switch (property_id) {\n";
List.iter (
- fun optargt ->
+ function OStringList _ -> () (* XXX *)
+ | optargt ->
let optname = name_of_optargt optargt in
let uc_optname = String.uppercase optname in
pr " case PROP_GUESTFS_%s_%s:\n" uc_name uc_optname;
@@ -441,6 +444,7 @@ let generate_gobject_optargs_source name optargs f ()
| OInt _ -> "int"
| OInt64 _ -> "int64"
| OString _ -> "string"
+ | OStringList _ -> "" (* XXX *)
in
pr " g_value_set_%s(value, priv->%s);\n" set_value_func
optname;
pr " break;\n\n";
@@ -460,6 +464,7 @@ let generate_gobject_optargs_source name optargs f ()
function
| OString n ->
pr " g_free(priv->%s);\n" n
+ | OStringList n -> () (* XXX *)
| OBool _ | OInt _ | OInt64 _ -> ()
) optargs;
pr "\n";
@@ -475,7 +480,8 @@ let generate_gobject_optargs_source name optargs f () pr
" object_class->get_property = guestfs_%s_get_property;\n\n" name;
List.iter (
- fun optargt ->
+ function OStringList _ -> () (* XXX *)
+ | optargt ->
let optname = name_of_optargt optargt in
let type_spec, type_init, type_desc match optargt with
@@ -487,6 +493,7 @@ let generate_gobject_optargs_source name optargs f ()
"int64", "G_MININT64, G_MAXINT64, -1", "A 64-bit
integer."
| OString n ->
"string", "NULL", "A string."
+ | OStringList n -> "", "", "" (* XXX
*)
in
pr " /**\n";
pr " * %s:%s:\n" camel_name optname;
@@ -1140,6 +1147,8 @@ guestfs_session_close(GuestfsSession *session, GError
**err)
set_property n "gint64 " "G_TYPE_INT64"
"int64" "-1"
| OString n ->
set_property n "const gchar *" "G_TYPE_STRING"
"string" "NULL"
+ | OStringList n ->
+ () (* XXX *)
) optargs;
pr " argvp = &argv;\n";
pr " }\n"
diff --git a/generator/generator_java.ml b/generator/generator_java.ml
index d239e1f..369b8aa 100644
--- a/generator/generator_java.ml
+++ b/generator/generator_java.ml
@@ -144,7 +144,8 @@ public class GuestFS {
| OBool n -> "boolean", "Boolean",
".booleanValue()", n, "false"
| OInt n -> "int", "Integer",
".intValue()", n, "0"
| OInt64 n -> "long", "Long",
".longValue()", n, "0"
- | OString n -> "String", "String",
"", n, "\"\"" in
+ | OString n -> "String", "String",
"", n, "\"\""
+ | OStringList n -> "String[]", "String[]",
"", n, "new String[]{}" in
pr " %s %s = %s;\n" t n default;
pr " _optobj = null;\n";
pr " if (optargs != null)\n";
@@ -343,6 +344,7 @@ and generate_java_prototype ?(public=false) ?(privat=false)
?(native=false)
| OInt n -> pr ", int %s" n
| OInt64 n -> pr ", long %s" n
| OString n -> pr ", String %s" n
+ | OStringList n -> pr ", String[] %s" n
) optargs
)
);
@@ -480,6 +482,7 @@ Java_com_redhat_et_libguestfs_GuestFS__1close
| OInt n -> pr ", jint j%s" n
| OInt64 n -> pr ", jlong j%s" n
| OString n -> pr ", jstring j%s" n
+ | OStringList n -> pr ", jobjectArray j%s" n
) optargs
);
pr ")\n";
@@ -546,7 +549,15 @@ Java_com_redhat_et_libguestfs_GuestFS__1close
if optargs <> [] then (
pr " struct %s optargs_s;\n" c_function;
- pr " const struct %s *optargs = &optargs_s;\n"
c_function
+ pr " const struct %s *optargs = &optargs_s;\n"
c_function;
+
+ List.iter (
+ function
+ | OBool _ | OInt _ | OInt64 _ | OString _ -> ()
+ | OStringList n ->
+ pr " size_t %s_len;\n" n;
+ pr " char **%s;\n" n
+ ) optargs
);
let needs_i @@ -556,9 +567,12 @@
Java_com_redhat_et_libguestfs_GuestFS__1close
| RConstOptString _
| RString _ | RBufferOut _ | RStruct _ -> false) ||
List.exists (function
- | StringList _ -> true
- | DeviceList _ -> true
- | _ -> false) args in
+ | StringList _ -> true
+ | DeviceList _ -> true
+ | _ -> false) args ||
+ List.exists (function
+ | OStringList _ -> true
+ | _ -> false) optargs in
if needs_i then
pr " size_t i;\n";
@@ -600,7 +614,7 @@ Java_com_redhat_et_libguestfs_GuestFS__1close
) args;
if optargs <> [] then (
- pr " optargs_s.bitmask = joptargs_bitmask;\n";
+ pr "\n";
List.iter (
function
| OBool n | OInt n | OInt64 n ->
@@ -608,7 +622,18 @@ Java_com_redhat_et_libguestfs_GuestFS__1close
| OString n ->
pr " optargs_s.%s = (*env)->GetStringUTFChars (env, j%s,
NULL);\n"
n n
+ | OStringList n ->
+ pr " %s_len = (*env)->GetArrayLength (env, j%s);\n" n
n;
+ pr " %s = guestfs_safe_malloc (g, sizeof (char *) *
(%s_len+1));\n" n n;
+ pr " for (i = 0; i < %s_len; ++i) {\n" n;
+ pr " jobject o = (*env)->GetObjectArrayElement (env,
j%s, i);\n"
+ n;
+ pr " %s[i] = (char *) (*env)->GetStringUTFChars (env, o,
NULL);\n" n;
+ pr " }\n";
+ pr " %s[%s_len] = NULL;\n" n n;
+ pr " optargs_s.%s = %s;\n" n n
) optargs;
+ pr " optargs_s.bitmask = joptargs_bitmask;\n";
);
pr "\n";
@@ -653,6 +678,13 @@ Java_com_redhat_et_libguestfs_GuestFS__1close
| OBool n | OInt n | OInt64 n -> ()
| OString n ->
pr " (*env)->ReleaseStringUTFChars (env, j%s,
optargs_s.%s);\n" n n
+ | OStringList n ->
+ pr " for (i = 0; i < %s_len; ++i) {\n" n;
+ pr " jobject o = (*env)->GetObjectArrayElement (env,
j%s, i);\n"
+ n;
+ pr " (*env)->ReleaseStringUTFChars (env, o,
optargs_s.%s[i]);\n" n;
+ pr " }\n";
+ pr " free (%s);\n" n
) optargs;
pr "\n";
diff --git a/generator/generator_ocaml.ml b/generator/generator_ocaml.ml
index db31655..1e088f1 100644
--- a/generator/generator_ocaml.ml
+++ b/generator/generator_ocaml.ml
@@ -532,6 +532,8 @@ copy_table (char * const * argv)
| OInt64 _ -> pr "Int64_val (Field (%sv, 0))" n
| OString _ ->
pr "guestfs_safe_strdup (g, String_val (Field (%sv,
0)))" n
+ | OStringList n ->
+ pr "ocaml_guestfs_strings_val (g, Field (%sv, 0))\n"
n
);
pr ";\n";
pr " }\n";
@@ -584,6 +586,9 @@ copy_table (char * const * argv)
| OString n ->
pr " if (%sv != Val_int (0))\n" n;
pr " free ((char *) optargs_s.%s);\n" n
+ | OStringList n ->
+ pr " if (%sv != Val_int (0))\n" n;
+ pr " ocaml_guestfs_free_strings ((char **)
optargs_s.%s);\n" n;
) optargs;
(match errcode_of_ret ret with
@@ -693,6 +698,7 @@ and generate_ocaml_function_type ?(extra_unit = false) (ret,
args, optargs) | OInt n -> pr "?%s:int -> " n
| OInt64 n -> pr "?%s:int64 -> " n
| OString n -> pr "?%s:string -> " n
+ | OStringList n -> pr "?%s:string array -> " n
) optargs;
List.iter (
function
diff --git a/generator/generator_perl.ml b/generator/generator_perl.ml
index ced0ed6..a159f99 100644
--- a/generator/generator_perl.ml
+++ b/generator/generator_perl.ml
@@ -417,14 +417,33 @@ user_cancel (g)
let n = name_of_optargt argt in
let uc_n = String.uppercase n in
pr "if (strcmp (this_arg, \"%s\") == 0) {\n" n;
- pr " optargs_s.%s = " n;
(match argt with
| OBool _
| OInt _
- | OInt64 _ -> pr "SvIV (ST (items_i+1))"
- | OString _ -> pr "SvPV_nolen (ST (items_i+1))"
+ | OInt64 _ ->
+ pr " optargs_s.%s = SvIV (ST (items_i+1));\n"
n;
+ | OString _ ->
+ pr " optargs_s.%s = SvPV_nolen (ST
(items_i+1));\n" n;
+ | OStringList _ ->
+ pr " size_t i, len;\n";
+ pr " char **r;\n";
+ pr " AV *av;\n";
+ pr " SV **svp;\n";
+ pr "\n";
+ pr " /* XXX More checking required here.
*/\n";
+ pr " av = (AV *) SvRV (ST (items_i+1));\n";
+ pr "\n";
+ pr " /* Note av_len returns index of final
element. */\n";
+ pr " len = av_len (av) + 1;\n";
+ pr "\n";
+ pr " r = malloc ((len+1) * sizeof (char
*));\n";
+ pr " for (i = 0; i < len; ++i) {\n";
+ pr " svp = av_fetch (av, i, 0);\n";
+ pr " r[i] = SvPV_nolen (*svp);\n";
+ pr " }\n";
+ pr " r[i] = NULL;\n";
+ pr " optargs_s.%s = r;\n" n
);
- pr ";\n";
pr " this_mask = %s_%s_BITMASK;\n"
c_optarg_prefix uc_n;
pr " }\n";
pr " else ";
diff --git a/generator/generator_php.ml b/generator/generator_php.ml
index a382240..42983ef 100644
--- a/generator/generator_php.ml
+++ b/generator/generator_php.ml
@@ -220,6 +220,8 @@ PHP_FUNCTION (guestfs_last_error)
| OString n ->
pr " char *optargs_t_%s = NULL;\n" n;
pr " int optargs_t_%s_size = -1;\n" n
+ | OStringList n ->
+ pr " zval *z_%s;\n" n
) optargs
);
@@ -247,6 +249,7 @@ PHP_FUNCTION (guestfs_last_error)
| OBool _ -> "b"
| OInt _ | OInt64 _ -> "l"
| OString _ -> "s"
+ | OStringList _ -> "a"
) optargs
)
else param_string in
@@ -273,6 +276,8 @@ PHP_FUNCTION (guestfs_last_error)
pr ", &optargs_t_%s" n
| OString n ->
pr ", &optargs_t_%s, &optargs_t_%s_size" n n
+ | OStringList n ->
+ pr ", &z_%s" n
) optargs;
pr ") == FAILURE) {\n";
pr " RETURN_FALSE;\n";
@@ -332,19 +337,52 @@ PHP_FUNCTION (guestfs_last_error)
(* Optional arguments. *)
if optargs <> [] then (
List.iter (
- fun argt ->
- let n = name_of_optargt argt in
+ function
+ | OBool n ->
+ let uc_n = String.uppercase n in
+ pr " if (optargs_t_%s != (zend_bool)-1) {\n" n;
+ pr " optargs_s.%s = optargs_t_%s;\n" n n;
+ pr " optargs_s.bitmask |= %s_%s_BITMASK;\n"
c_optarg_prefix uc_n;
+ pr " }\n"
+ | OInt n | OInt64 n ->
+ let uc_n = String.uppercase n in
+ pr " if (optargs_t_%s != -1) {\n" n;
+ pr " optargs_s.%s = optargs_t_%s;\n" n n;
+ pr " optargs_s.bitmask |= %s_%s_BITMASK;\n"
c_optarg_prefix uc_n;
+ pr " }\n"
+ | OString n ->
let uc_n = String.uppercase n in
- pr " if (optargs_t_%s != " n;
- (match argt with
- | OBool _ -> pr "((zend_bool)-1)"
- | OInt _ | OInt64 _ -> pr "-1"
- | OString _ -> pr "NULL"
- );
- pr ") {\n";
+ pr " if (optargs_t_%s != NULL) {\n" n;
pr " optargs_s.%s = optargs_t_%s;\n" n n;
pr " optargs_s.bitmask |= %s_%s_BITMASK;\n"
c_optarg_prefix uc_n;
pr " }\n"
+ | OStringList n ->
+ let uc_n = String.uppercase n in
+ pr " if (z_%s != NULL) {\n" n;
+ pr " char **r;\n";
+ pr " HashTable *a;\n";
+ pr " int n;\n";
+ pr " HashPosition p;\n";
+ pr " zval **d;\n";
+ pr " size_t c = 0;\n";
+ pr "\n";
+ pr " a = Z_ARRVAL_P (z_%s);\n" n;
+ pr " n = zend_hash_num_elements (a);\n";
+ pr " r = safe_emalloc (n + 1, sizeof (char *), 0);\n";
+ pr " for (zend_hash_internal_pointer_reset_ex (a,
&p);\n";
+ pr " zend_hash_get_current_data_ex (a, (void **)
&d, &p) == SUCCESS;\n";
+ pr " zend_hash_move_forward_ex (a, &p)) {\n";
+ pr " zval t = **d;\n";
+ pr " zval_copy_ctor (&t);\n";
+ pr " convert_to_string (&t);\n";
+ pr " r[c] = Z_STRVAL (t);\n";
+ pr " c++;\n";
+ pr " }\n";
+ pr " r[c] = NULL;\n";
+ pr " optargs_s.%s = r;\n" n;
+ pr "\n";
+ pr " optargs_s.bitmask |= %s_%s_BITMASK;\n"
c_optarg_prefix uc_n;
+ pr " }\n";
) optargs;
pr "\n"
);
diff --git a/generator/generator_python.ml b/generator/generator_python.ml
index dc2cd28..4ffc478 100644
--- a/generator/generator_python.ml
+++ b/generator/generator_python.ml
@@ -311,6 +311,7 @@ free_strings (char **argv)
| OInt n -> pr " int optargs_t_%s = -1;\n" n
| OInt64 n -> pr " long long optargs_t_%s = -1;\n" n
| OString n -> pr " const char *optargs_t_%s = NULL;\n"
n
+ | OStringList n -> pr " PyObject *py_%s;\n" n
) optargs
);
@@ -346,6 +347,7 @@ free_strings (char **argv)
| OBool _ | OInt _ -> pr "i"
| OInt64 _ -> pr "L"
| OString _ -> pr "z" (* because we use None to mean not
set *)
+ | OStringList _ -> pr "O"
) optargs;
);
@@ -367,6 +369,7 @@ free_strings (char **argv)
List.iter (
function
| OBool n | OInt n | OInt64 n | OString n -> pr ",
&optargs_t_%s" n
+ | OStringList n -> pr ", &py_%s" n
) optargs;
pr "))\n";
@@ -389,18 +392,26 @@ free_strings (char **argv)
if optargs <> [] then (
List.iter (
- fun argt ->
- let n = name_of_optargt argt in
+ function
+ | OBool n | OInt n | OInt64 n ->
+ let uc_n = String.uppercase n in
+ pr " if (optargs_t_%s != -1) {\n" n;
+ pr " optargs_s.%s = optargs_t_%s;\n" n n;
+ pr " optargs_s.bitmask |= %s_%s_BITMASK;\n"
c_optarg_prefix uc_n;
+ pr " }\n"
+ | OString n ->
let uc_n = String.uppercase n in
- pr " if (optargs_t_%s != " n;
- (match argt with
- | OBool _ | OInt _ | OInt64 _ -> pr "-1"
- | OString _ -> pr "NULL"
- );
- pr ") {\n";
+ pr " if (optargs_t_%s != NULL) {\n" n;
pr " optargs_s.%s = optargs_t_%s;\n" n n;
pr " optargs_s.bitmask |= %s_%s_BITMASK;\n"
c_optarg_prefix uc_n;
pr " }\n"
+ | OStringList n ->
+ let uc_n = String.uppercase n in
+ pr " if (py_%s != Py_None) {\n" n;
+ pr " optargs_s.%s = get_string_list (py_%s);\n" n n;
+ pr " if (!optargs_s.%s) return NULL;\n" n;
+ pr " optargs_s.bitmask |= %s_%s_BITMASK;\n"
c_optarg_prefix uc_n;
+ pr " }\n"
) optargs;
pr "\n"
);
@@ -431,6 +442,14 @@ free_strings (char **argv)
pr " free (%s);\n" n
) args;
+ List.iter (
+ function
+ | OBool _ | OInt _ | OInt64 _ | OString _ -> ()
+ | OStringList n ->
+ pr " if (py_%s != Py_None)\n" n;
+ pr " free (optargs_s.%s);\n" n
+ ) optargs;
+
(match errcode_of_ret ret with
| `CannotReturnError -> ()
| `ErrorIsMinusOne ->
@@ -706,7 +725,7 @@ class GuestFS:
List.iter (
function
| OBool n | OInt n | OInt64 n -> pr ", %s=-1" n
- | OString n -> pr ", %s=None" n
+ | OString n | OStringList n -> pr ", %s=None" n
) optargs;
pr "):\n";
diff --git a/generator/generator_ruby.ml b/generator/generator_ruby.ml
index f962117..ec66fbd 100644
--- a/generator/generator_ruby.ml
+++ b/generator/generator_ruby.ml
@@ -535,6 +535,21 @@ ruby_user_cancel (VALUE gv)
pr " optargs_s.%s = NUM2LL (v);\n" n;
| OString _ ->
pr " optargs_s.%s = StringValueCStr (v);\n" n
+ | OStringList _ ->
+ pr " Check_Type (v, T_ARRAY);\n";
+ pr " {\n";
+ pr " size_t i, len;\n";
+ pr " char **r;\n";
+ pr "\n";
+ pr " len = RARRAY_LEN (v);\n";
+ pr " r = ALLOC_N (char *, len+1);\n";
+ pr " for (i = 0; i < len; ++i) {\n";
+ pr " volatile VALUE sv = rb_ary_entry (v, i);\n";
+ pr " r[i] = StringValueCStr (sv);\n";
+ pr " }\n";
+ pr " r[len] = NULL;\n";
+ pr " optargs_s.%s = r;\n" n;
+ pr " }\n"
);
pr " optargs_s.bitmask |= %s_%s_BITMASK;\n"
c_optarg_prefix uc_n;
pr " }\n";
diff --git a/generator/generator_tests_c_api.ml
b/generator/generator_tests_c_api.ml
index 83087da..4daa9e4 100644
--- a/generator/generator_tests_c_api.ml
+++ b/generator/generator_tests_c_api.ml
@@ -852,7 +852,22 @@ and generate_test_command_call ?(expect_error = false)
?test test_name cmd pr " optargs.%s = %Ld;\n" n
i; true
| OString n, "NOARG" -> false
| OString n, arg ->
- pr " optargs.%s = \"%s\";\n" n
(c_quote arg); true in
+ pr " optargs.%s = \"%s\";\n" n
(c_quote arg); true
+ | OStringList n, "NOARG" -> false
+ | OStringList n, "" ->
+ pr " const char *const %s[1] = { NULL };\n" n;
true
+ | OStringList n, arg ->
+ let strs = string_split " " arg in
+ iteri (
+ fun i str ->
+ pr " const char *%s_%d =
\"%s\";\n" n i (c_quote str);
+ ) strs;
+ pr " const char *const %s[] = {\n" n;
+ iteri (
+ fun i _ -> pr " %s_%d,\n" n i
+ ) strs;
+ pr " NULL\n";
+ pr " };\n"; true in
let bit = if is_set then Int64.shift_left 1L shift else 0L in
let bitmask = Int64.logor bitmask bit in
let shift = shift + 1 in
diff --git a/generator/generator_types.ml b/generator/generator_types.ml
index aeb751c..8ab6d0a 100644
--- a/generator/generator_types.ml
+++ b/generator/generator_types.ml
@@ -210,6 +210,8 @@ and optargt | OInt of string (* int (smallish ints,
signed, <= 31 bits) *)
| OInt64 of string (* any 64 bit int *)
| OString of string (* const char *name, cannot be NULL *)
+ | OStringList of string (* char **strings, neither the list nor any
+ string may be NULL *)
type errcode = [ `CannotReturnError | `ErrorIsMinusOne | `ErrorIsNULL ]
@@ -451,3 +453,4 @@ type call_optargt | CallOInt of string * int
| CallOInt64 of string * int64
| CallOString of string * string
+ | CallOStringList of string * string list
diff --git a/generator/generator_utils.ml b/generator/generator_utils.ml
index 3351bf9..a4e19d5 100644
--- a/generator/generator_utils.ml
+++ b/generator/generator_utils.ml
@@ -256,7 +256,7 @@ let name_of_argt = function
| FileIn n | FileOut n | BufferIn n | Key n | Pointer (_, n) -> n
let name_of_optargt = function
- | OBool n | OInt n | OInt64 n | OString n -> n
+ | OBool n | OInt n | OInt64 n | OString n | OStringList n -> n
let seq_of_test = function
| TestRun s | TestOutput (s, _) | TestOutputList (s, _)
@@ -360,4 +360,5 @@ let args_of_optargs optargs | OInt n -> Int n
| OInt64 n -> Int64 n
| OString n -> String n
+ | OStringList n -> StringList n
) optargs;
diff --git a/gobject/run-tests b/gobject/run-tests
index 6bcd94e..8b3f78a 100755
--- a/gobject/run-tests
+++ b/gobject/run-tests
@@ -23,6 +23,14 @@ if [ -z "$GJS" ]; then
exit 77
fi
+rm -f bindtests.tmp
+
$GJS $srcdir/bindtests.js > bindtests.tmp
-diff -u ${srcdir}/../bindtests bindtests.tmp
+
+# OStringList is not implemented in GObject bindings yet,
+# so we have to hack the results. XXX
+diff -I ^ostringlist: -u ${srcdir}/../bindtests bindtests.tmp
+
$GJS $srcdir/bindtests-manual.js 2>/dev/null
+
+rm bindtests.tmp
--
1.7.10.4
Richard W.M. Jones
2012-Aug-14 14:51 UTC
[Libguestfs] [PATCH 7/7] tar-out: Add list of excluded patterns (--exclude=...) (RHBZ#847881).
From: "Richard W.M. Jones" <rjones at redhat.com>
---
daemon/tar.c | 64 ++++++++++++++++++++++++++++++++++++----
generator/generator_actions.ml | 7 ++++-
2 files changed, 65 insertions(+), 6 deletions(-)
diff --git a/daemon/tar.c b/daemon/tar.c
index f46733d..6a894e6 100644
--- a/daemon/tar.c
+++ b/daemon/tar.c
@@ -237,14 +237,53 @@ do_txz_in (const char *dir)
return do_tar_in (dir, "xz");
}
+/* Turn list 'excludes' into list of " --excludes=..."
strings, all
+ * properly quoted. Caller must free the returned string.
+ */
+static char *
+make_excludes_args (char *const *excludes)
+{
+ DECLARE_STRINGSBUF (strings);
+ size_t i;
+ char *s, *ret;
+
+ for (i = 0; excludes[i] != NULL; ++i) {
+ if (asprintf_nowarn (&s, " --exclude=%Q", excludes[i]) == -1)
{
+ reply_with_perror ("asprintf");
+ free_stringslen (strings.argv, strings.size);
+ return NULL;
+ }
+ if (!add_string_nodup (&strings, s) == -1) {
+ free (s);
+ return NULL;
+ }
+ }
+
+ if (end_stringsbuf (&strings) == -1)
+ return NULL;
+
+ ret = concat_strings (&strings);
+ if (!ret) {
+ reply_with_perror ("concat");
+ free_stringslen (strings.argv, strings.size);
+ return NULL;
+ }
+
+ free_stringslen (strings.argv, strings.size);
+
+ return ret;
+}
+
/* Has one FileOut parameter. */
/* Takes optional arguments, consult optargs_bitmask. */
int
-do_tar_out (const char *dir, const char *compress, int numericowner)
+do_tar_out (const char *dir, const char *compress, int numericowner,
+ char *const *excludes)
{
const char *filter;
int r;
FILE *fp;
+ char *excludes_args;
char *cmd;
char buf[GUESTFS_MAX_CHUNK_SIZE];
@@ -269,13 +308,28 @@ do_tar_out (const char *dir, const char *compress, int
numericowner)
if (!(optargs_bitmask & GUESTFS_TAR_OUT_NUMERICOWNER_BITMASK))
numericowner = 0;
+ if (!(optargs_bitmask & GUESTFS_TAR_OUT_EXCLUDES_BITMASK)) {
+ excludes_args = make_excludes_args (excludes);
+ if (!excludes_args)
+ return -1;
+ } else {
+ excludes_args = strdup ("");
+ if (excludes_args == NULL) {
+ reply_with_perror ("strdup");
+ return -1;
+ }
+ }
+
/* "tar -C /sysroot%s -cf - ." but we have to quote the dir. */
- if (asprintf_nowarn (&cmd, "tar -C %R%s%s -cf - .",
+ if (asprintf_nowarn (&cmd, "tar -C %R%s%s%s -cf - .",
dir, filter,
- numericowner ? " --numeric-owner" :
"") == -1) {
+ numericowner ? " --numeric-owner" :
"",
+ excludes_args) == -1) {
reply_with_perror ("asprintf");
+ free (excludes_args);
return -1;
}
+ free (excludes_args);
if (verbose)
fprintf (stderr, "%s\n", cmd);
@@ -325,7 +379,7 @@ int
do_tgz_out (const char *dir)
{
optargs_bitmask = GUESTFS_TAR_OUT_COMPRESS_BITMASK;
- return do_tar_out (dir, "gzip", 0);
+ return do_tar_out (dir, "gzip", 0, NULL);
}
/* Has one FileOut parameter. */
@@ -333,5 +387,5 @@ int
do_txz_out (const char *dir)
{
optargs_bitmask = GUESTFS_TAR_OUT_COMPRESS_BITMASK;
- return do_tar_out (dir, "bzip2", 0);
+ return do_tar_out (dir, "bzip2", 0, NULL);
}
diff --git a/generator/generator_actions.ml b/generator/generator_actions.ml
index 19c81be..7db88ce 100644
--- a/generator/generator_actions.ml
+++ b/generator/generator_actions.ml
@@ -3434,7 +3434,7 @@ compression types)." };
{ defaults with
name = "tar_out";
- style = RErr, [String "directory"; FileOut "tarfile"],
[OString "compress"; OBool "numericowner"];
+ style = RErr, [String "directory"; FileOut "tarfile"],
[OString "compress"; OBool "numericowner"; OStringList
"excludes"];
proc_nr = Some 70;
once_had_no_optargs = true;
cancellable = true;
@@ -3454,6 +3454,11 @@ The other optional arguments are:
=over 4
+=item C<excludes>
+
+A list of wildcards. Files are excluded if they match any of the
+wildcards.
+
=item C<numericowner>
If set to true, the output tar file will contain UID/GID numbers
--
1.7.10.4
Maybe Matching Threads
- [PATCH 1/2] generator: Rename java_structs to camel_structs to better reflect their purpose
- [PATCH 1/4] php: fix invalid memory access with OptString
- [PATCH] python: fix possible free on uninit memory with OStringList optargs
- [PATCH 3/3] python: Allow bindings to be compiled with different version of libguestfs (RHBZ#1262983).
- [PATCH 0/2] generator: Simplify the handling of string parameters.