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.