From d901cc916102f1aaccfb73396b48aa303e5b8cd7 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Thu, 14 May 2009 23:47:17 +0100 Subject: [PATCH] Add support for zerofree command. --- contrib/fedora-libguestfs.spec | 1 + daemon/Makefile.am | 1 + daemon/actions.h | 1 + daemon/stubs.c | 27 ++++++ daemon/zerofree.c | 48 ++++++++++ fish/cmds.c | 21 +++++ fish/completion.c | 1 + guestfish-actions.pod | 15 +++ guestfs-actions.pod | 18 ++++ haskell/Guestfs.hs | 15 ++- java/com/redhat/et/libguestfs/GuestFS.java | 26 ++++++ java/com_redhat_et_libguestfs_GuestFS.c | 17 ++++ make-initramfs.sh.in | 1 + ocaml/guestfs.ml | 1 + ocaml/guestfs.mli | 3 + ocaml/guestfs_c_actions.c | 23 +++++ perl/Guestfs.xs | 11 +++ perl/lib/Sys/Guestfs.pm | 13 +++ python/guestfs-py.c | 26 ++++++ python/guestfs.py | 14 +++ ruby/ext/guestfs/_guestfs.c | 23 +++++ src/generator.ml | 23 +++++ src/guestfs-actions.c | 87 +++++++++++++++++ src/guestfs-actions.h | 1 + src/guestfs_protocol.c | 10 ++ src/guestfs_protocol.h | 10 +- src/guestfs_protocol.x | 5 + tests.c | 145 ++++++++++++++++++++++++----- 28 files changed, 561 insertions(+), 26 deletions(-) create mode 100644 daemon/zerofree.c diff --git a/contrib/fedora-libguestfs.spec b/contrib/fedora-libguestfs.spec index b7d66ba..9c3e3ed 100644 --- a/contrib/fedora-libguestfs.spec +++ b/contrib/fedora-libguestfs.spec @@ -36,6 +36,7 @@ BuildRequires: kernel, bash, coreutils, lvm2, ntfs-3g, util-linux-ng BuildRequires: MAKEDEV, net-tools, augeas-libs, file BuildRequires: module-init-tools, procps, strace, iputils BuildRequires: grub, dosfstools, ntfsprogs +BuildRequires: zerofree # These are only required if you want to build the bindings for # different languages: diff --git a/daemon/Makefile.am b/daemon/Makefile.am index 8460d44..d6ae6c3 100644 --- a/daemon/Makefile.am +++ b/daemon/Makefile.am @@ -50,6 +50,7 @@ guestfsd_SOURCES = \ tar.c \ upload.c \ zero.c \ + zerofree.c \ ../src/guestfs_protocol.h \ ../src/guestfs_protocol.c diff --git a/daemon/actions.h b/daemon/actions.h index f4678f8..37ec125 100644 --- a/daemon/actions.h +++ b/daemon/actions.h @@ -117,3 +117,4 @@ extern int do_equal (const char *file1, const char *file2); extern char **do_strings (const char *path); extern char **do_strings_e (const char *encoding, const char *path); extern char *do_hexdump (const char *path); +extern int do_zerofree (const char *device); diff --git a/daemon/stubs.c b/daemon/stubs.c index 0e5b351..212634f 100644 --- a/daemon/stubs.c +++ b/daemon/stubs.c @@ -2397,6 +2397,30 @@ done: xdr_free ((xdrproc_t) xdr_guestfs_hexdump_args, (char *) &args); } +static void zerofree_stub (XDR *xdr_in) +{ + int r; + struct guestfs_zerofree_args args; + const char *device; + + memset (&args, 0, sizeof args); + + if (!xdr_guestfs_zerofree_args (xdr_in, &args)) { + reply_with_error ("%s: daemon failed to decode procedure arguments", "zerofree"); + return; + } + device = args.device; + + r = do_zerofree (device); + if (r == -1) + /* do_zerofree has already called reply_with_error */ + goto done; + + reply (NULL, NULL); +done: + xdr_free ((xdrproc_t) xdr_guestfs_zerofree_args, (char *) &args); +} + void dispatch_incoming_message (XDR *xdr_in) { switch (proc_nr) { @@ -2688,6 +2712,9 @@ void dispatch_incoming_message (XDR *xdr_in) case GUESTFS_PROC_HEXDUMP: hexdump_stub (xdr_in); break; + case GUESTFS_PROC_ZEROFREE: + zerofree_stub (xdr_in); + break; default: reply_with_error ("dispatch_incoming_message: unknown procedure number %d", proc_nr); } diff --git a/daemon/zerofree.c b/daemon/zerofree.c new file mode 100644 index 0000000..b44965a --- /dev/null +++ b/daemon/zerofree.c @@ -0,0 +1,48 @@ +/* libguestfs - the guestfsd daemon + * Copyright (C) 2009 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include + +#include +#include +#include +#include +#include + +#include "daemon.h" +#include "actions.h" + +int +do_zerofree (const char *device) +{ + char *err; + int r; + + IS_DEVICE (device, -1); + + r = command (NULL, &err, "/usr/sbin/zerofree", device, NULL); + if (r == -1) { + reply_with_error ("zerofree: %s: %s", device, err); + free (err); + return -1; + } + + free (err); + + return 0; +} diff --git a/fish/cmds.c b/fish/cmds.c index 1e442d8..1f3d9ce 100644 --- a/fish/cmds.c +++ b/fish/cmds.c @@ -147,6 +147,7 @@ void list_commands (void) printf ("%-20s %s\n", "vgs-full", "list the LVM volume groups (VGs)"); printf ("%-20s %s\n", "write-file", "create a file"); printf ("%-20s %s\n", "zero", "write zeroes to the device"); + printf ("%-20s %s\n", "zerofree", "zero unused inodes and disk blocks on ext2/3 filesystem"); printf (" Use -h / help to show detailed help for a command.\n"); } @@ -500,6 +501,9 @@ void display_command (const char *cmd) if (strcasecmp (cmd, "hexdump") == 0) pod2text ("hexdump - dump a file in hexadecimal", " hexdump \n\nThis runs C on the given C. The result is\nthe human-readable, canonical hex dump of the file.\n\nBecause of the message protocol, there is a transfer limit \nof somewhere between 2MB and 4MB. To transfer large files you should use\nFTP."); else + if (strcasecmp (cmd, "zerofree") == 0) + pod2text ("zerofree - zero unused inodes and disk blocks on ext2/3 filesystem", " zerofree \n\nThis runs the I program on C. This program\nclaims to zero unused inodes and disk blocks on an ext2/3\nfilesystem, thus making it possible to compress the filesystem\nmore effectively.\n\nYou should B run this program if the filesystem is\nmounted.\n\nIt is possible that using this program can damage the filesystem\nor data on the filesystem."); + else display_builtin_command (cmd); } @@ -2438,6 +2442,20 @@ static int run_hexdump (const char *cmd, int argc, char *argv[]) return 0; } +static int run_zerofree (const char *cmd, int argc, char *argv[]) +{ + int r; + const char *device; + if (argc != 1) { + fprintf (stderr, "%s should have 1 parameter(s)\n", cmd); + fprintf (stderr, "type 'help %s' for help on %s\n", cmd, cmd); + return -1; + } + device = argv[0]; + r = guestfs_zerofree (g, device); + return r; +} + int run_action (const char *cmd, int argc, char *argv[]) { if (strcasecmp (cmd, "launch") == 0 || strcasecmp (cmd, "run") == 0) @@ -2788,6 +2806,9 @@ int run_action (const char *cmd, int argc, char *argv[]) if (strcasecmp (cmd, "hexdump") == 0) return run_hexdump (cmd, argc, argv); else + if (strcasecmp (cmd, "zerofree") == 0) + return run_zerofree (cmd, argc, argv); + else { fprintf (stderr, "%s: unknown command\n", cmd); return -1; diff --git a/fish/completion.c b/fish/completion.c index 4db2d5e..5c7f5e0 100644 --- a/fish/completion.c +++ b/fish/completion.c @@ -160,6 +160,7 @@ static const char *const commands[] = { "vgs-full", "write-file", "zero", + "zerofree", NULL }; diff --git a/guestfish-actions.pod b/guestfish-actions.pod index 9146c41..7b5a4be 100644 --- a/guestfish-actions.pod +++ b/guestfish-actions.pod @@ -1283,3 +1283,18 @@ How many blocks are zeroed isn't specified (but it's I enough to securely wipe the device). It should be sufficient to remove any partition tables, filesystem superblocks and so on. +=head2 zerofree + + zerofree device + +This runs the I program on C. This program +claims to zero unused inodes and disk blocks on an ext2/3 +filesystem, thus making it possible to compress the filesystem +more effectively. + +You should B run this program if the filesystem is +mounted. + +It is possible that using this program can damage the filesystem +or data on the filesystem. + diff --git a/guestfs-actions.pod b/guestfs-actions.pod index 53bfa54..109c73e 100644 --- a/guestfs-actions.pod +++ b/guestfs-actions.pod @@ -1747,3 +1747,21 @@ any partition tables, filesystem superblocks and so on. This function returns 0 on success or -1 on error. +=head2 guestfs_zerofree + + int guestfs_zerofree (guestfs_h *handle, + const char *device); + +This runs the I program on C. This program +claims to zero unused inodes and disk blocks on an ext2/3 +filesystem, thus making it possible to compress the filesystem +more effectively. + +You should B run this program if the filesystem is +mounted. + +It is possible that using this program can damage the filesystem +or data on the filesystem. + +This function returns 0 on success or -1 on error. + diff --git a/haskell/Guestfs.hs b/haskell/Guestfs.hs index 4721376..c061a7a 100644 --- a/haskell/Guestfs.hs +++ b/haskell/Guestfs.hs @@ -78,7 +78,8 @@ module Guestfs ( cp, cp_a, mv, - ping_daemon + ping_daemon, + zerofree ) where import Foreign import Foreign.C @@ -788,3 +789,15 @@ ping_daemon h = do fail err else return () +foreign import ccall unsafe "guestfs_zerofree" c_zerofree + :: GuestfsP -> CString -> IO (CInt) + +zerofree :: GuestfsH -> String -> IO () +zerofree h device = do + r <- withCString device $ \device -> withForeignPtr h (\p -> c_zerofree p device) + if (r == -1) + then do + err <- last_error h + fail err + else return () + diff --git a/java/com/redhat/et/libguestfs/GuestFS.java b/java/com/redhat/et/libguestfs/GuestFS.java index c816baa..76ada90 100644 --- a/java/com/redhat/et/libguestfs/GuestFS.java +++ b/java/com/redhat/et/libguestfs/GuestFS.java @@ -2729,4 +2729,30 @@ public class GuestFS { private native String _hexdump (long g, String path) throws LibGuestFSException; + /** + * zero unused inodes and disk blocks on ext2/3 filesystem + * + * This runs the *zerofree* program on "device". This + * program claims to zero unused inodes and disk blocks on + * an ext2/3 filesystem, thus making it possible to + * compress the filesystem more effectively. + * + * You should not run this program if the filesystem is + * mounted. + * + * It is possible that using this program can damage the + * filesystem or data on the filesystem. + * + * @throws LibGuestFSException + */ + public void zerofree (String device) + throws LibGuestFSException + { + if (g == 0) + throw new LibGuestFSException ("zerofree: handle is closed"); + _zerofree (g, device); + } + private native void _zerofree (long g, String device) + throws LibGuestFSException; + } diff --git a/java/com_redhat_et_libguestfs_GuestFS.c b/java/com_redhat_et_libguestfs_GuestFS.c index ce1f2db..a823d84 100644 --- a/java/com_redhat_et_libguestfs_GuestFS.c +++ b/java/com_redhat_et_libguestfs_GuestFS.c @@ -2722,3 +2722,20 @@ Java_com_redhat_et_libguestfs_GuestFS__1hexdump return jr; } +JNIEXPORT void JNICALL +Java_com_redhat_et_libguestfs_GuestFS__1zerofree + (JNIEnv *env, jobject obj, jlong jg, jstring jdevice) +{ + guestfs_h *g = (guestfs_h *) (long) jg; + int r; + const char *device; + + device = (*env)->GetStringUTFChars (env, jdevice, NULL); + r = guestfs_zerofree (g, device); + (*env)->ReleaseStringUTFChars (env, jdevice, device); + if (r == -1) { + throw_exception (env, guestfs_last_error (g)); + return ; + } +} + diff --git a/make-initramfs.sh.in b/make-initramfs.sh.in index b8faa3b..b6e7820 100755 --- a/make-initramfs.sh.in +++ b/make-initramfs.sh.in @@ -41,6 +41,7 @@ modules=" -i procps -i strace -i util-linux-ng +-i zerofree " # Decide on names for the final output. These have to match Makefile.am. diff --git a/ocaml/guestfs.ml b/ocaml/guestfs.ml index 2544b16..3886022 100644 --- a/ocaml/guestfs.ml +++ b/ocaml/guestfs.ml @@ -235,3 +235,4 @@ external equal : t -> string -> string -> bool = "ocaml_guestfs_equal" external strings : t -> string -> string array = "ocaml_guestfs_strings" external strings_e : t -> string -> string -> string array = "ocaml_guestfs_strings_e" external hexdump : t -> string -> string = "ocaml_guestfs_hexdump" +external zerofree : t -> string -> unit = "ocaml_guestfs_zerofree" diff --git a/ocaml/guestfs.mli b/ocaml/guestfs.mli index 870ffb6..3776abe 100644 --- a/ocaml/guestfs.mli +++ b/ocaml/guestfs.mli @@ -484,3 +484,6 @@ val strings_e : t -> string -> string -> string array val hexdump : t -> string -> string (** dump a file in hexadecimal *) +val zerofree : t -> string -> unit +(** zero unused inodes and disk blocks on ext2/3 filesystem *) + diff --git a/ocaml/guestfs_c_actions.c b/ocaml/guestfs_c_actions.c index 22e6500..79a5c16 100644 --- a/ocaml/guestfs_c_actions.c +++ b/ocaml/guestfs_c_actions.c @@ -3178,3 +3178,26 @@ ocaml_guestfs_hexdump (value gv, value pathv) CAMLreturn (rv); } +CAMLprim value +ocaml_guestfs_zerofree (value gv, value devicev) +{ + CAMLparam2 (gv, devicev); + CAMLlocal1 (rv); + + guestfs_h *g = Guestfs_val (gv); + if (g == NULL) + caml_failwith ("zerofree: used handle after closing it"); + + const char *device = String_val (devicev); + int r; + + caml_enter_blocking_section (); + r = guestfs_zerofree (g, device); + caml_leave_blocking_section (); + if (r == -1) + ocaml_guestfs_raise_error (g, "zerofree"); + + rv = Val_unit; + CAMLreturn (rv); +} + diff --git a/perl/Guestfs.xs b/perl/Guestfs.xs index 973f56e..e87131b 100644 --- a/perl/Guestfs.xs +++ b/perl/Guestfs.xs @@ -1787,3 +1787,14 @@ PREINIT: OUTPUT: RETVAL +void +zerofree (g, device) + guestfs_h *g; + char *device; +PREINIT: + int r; + PPCODE: + r = guestfs_zerofree (g, device); + if (r == -1) + croak ("zerofree: %s", guestfs_last_error (g)); + diff --git a/perl/lib/Sys/Guestfs.pm b/perl/lib/Sys/Guestfs.pm index 13c084f..b11594f 100644 --- a/perl/lib/Sys/Guestfs.pm +++ b/perl/lib/Sys/Guestfs.pm @@ -1162,6 +1162,19 @@ How many blocks are zeroed isn't specified (but it's I enough to securely wipe the device). It should be sufficient to remove any partition tables, filesystem superblocks and so on. +=item $h->zerofree ($device); + +This runs the I program on C. This program +claims to zero unused inodes and disk blocks on an ext2/3 +filesystem, thus making it possible to compress the filesystem +more effectively. + +You should B run this program if the filesystem is +mounted. + +It is possible that using this program can damage the filesystem +or data on the filesystem. + =cut 1; diff --git a/python/guestfs-py.c b/python/guestfs-py.c index 3a09afb..8301c70 100644 --- a/python/guestfs-py.c +++ b/python/guestfs-py.c @@ -3402,6 +3402,31 @@ py_guestfs_hexdump (PyObject *self, PyObject *args) return py_r; } +static PyObject * +py_guestfs_zerofree (PyObject *self, PyObject *args) +{ + PyObject *py_g; + guestfs_h *g; + PyObject *py_r; + int r; + const char *device; + + if (!PyArg_ParseTuple (args, (char *) "Os:guestfs_zerofree", + &py_g, &device)) + return NULL; + g = get_handle (py_g); + + r = guestfs_zerofree (g, device); + if (r == -1) { + PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g)); + return NULL; + } + + Py_INCREF (Py_None); + py_r = Py_None; + return py_r; +} + static PyMethodDef methods[] = { { (char *) "create", py_guestfs_create, METH_VARARGS, NULL }, { (char *) "close", py_guestfs_close, METH_VARARGS, NULL }, @@ -3525,6 +3550,7 @@ static PyMethodDef methods[] = { { (char *) "strings", py_guestfs_strings, METH_VARARGS, NULL }, { (char *) "strings_e", py_guestfs_strings_e, METH_VARARGS, NULL }, { (char *) "hexdump", py_guestfs_hexdump, METH_VARARGS, NULL }, + { (char *) "zerofree", py_guestfs_zerofree, METH_VARARGS, NULL }, { NULL, NULL, 0, NULL } }; diff --git a/python/guestfs.py b/python/guestfs.py index e61ba65..044e1fa 100644 --- a/python/guestfs.py +++ b/python/guestfs.py @@ -1334,3 +1334,17 @@ class GuestFS: """ return libguestfsmod.hexdump (self._o, path) + def zerofree (self, device): + u"""This runs the *zerofree* program on "device". This + program claims to zero unused inodes and disk blocks on + an ext2/3 filesystem, thus making it possible to + compress the filesystem more effectively. + + You should not run this program if the filesystem is + mounted. + + It is possible that using this program can damage the + filesystem or data on the filesystem. + """ + return libguestfsmod.zerofree (self._o, device) + diff --git a/ruby/ext/guestfs/_guestfs.c b/ruby/ext/guestfs/_guestfs.c index 0c20703..4fb6ce7 100644 --- a/ruby/ext/guestfs/_guestfs.c +++ b/ruby/ext/guestfs/_guestfs.c @@ -2885,6 +2885,27 @@ static VALUE ruby_guestfs_hexdump (VALUE gv, VALUE pathv) return rv; } +static VALUE ruby_guestfs_zerofree (VALUE gv, VALUE devicev) +{ + guestfs_h *g; + Data_Get_Struct (gv, guestfs_h, g); + if (!g) + rb_raise (rb_eArgError, "%s: used handle after closing it", "zerofree"); + + const char *device = StringValueCStr (devicev); + if (!device) + rb_raise (rb_eTypeError, "expected string for parameter %s of %s", + "device", "zerofree"); + + int r; + + r = guestfs_zerofree (g, device); + if (r == -1) + rb_raise (e_Error, "%s", guestfs_last_error (g)); + + return Qnil; +} + /* Initialize the module. */ void Init__guestfs () { @@ -3135,4 +3156,6 @@ void Init__guestfs () ruby_guestfs_strings_e, 2); rb_define_method (c_guestfs, "hexdump", ruby_guestfs_hexdump, 1); + rb_define_method (c_guestfs, "zerofree", + ruby_guestfs_zerofree, 1); } diff --git a/src/generator.ml b/src/generator.ml index 82bfb88..652564d 100755 --- a/src/generator.ml +++ b/src/generator.ml @@ -1996,6 +1996,29 @@ The returned strings are transcoded to UTF-8."); This runs C on the given C. The result is the human-readable, canonical hex dump of the file."); + ("zerofree", (RErr, [String "device"]), 97, [], + [InitNone, Always, TestOutput ( + [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","]; + ["mkfs"; "ext3"; "/dev/sda1"]; + ["mount"; "/dev/sda1"; "/"]; + ["write_file"; "/new"; "test file"; "0"]; + ["umount"; "/dev/sda1"]; + ["zerofree"; "/dev/sda1"]; + ["mount"; "/dev/sda1"; "/"]; + ["cat"; "/new"]], "test file")], + "zero unused inodes and disk blocks on ext2/3 filesystem", + "\ +This runs the I program on C. This program +claims to zero unused inodes and disk blocks on an ext2/3 +filesystem, thus making it possible to compress the filesystem +more effectively. + +You should B run this program if the filesystem is +mounted. + +It is possible that using this program can damage the filesystem +or data on the filesystem."); + ] let all_functions = non_daemon_functions @ daemon_functions diff --git a/src/guestfs-actions.c b/src/guestfs-actions.c index 1296051..d27ef01 100644 --- a/src/guestfs-actions.c +++ b/src/guestfs-actions.c @@ -8809,3 +8809,90 @@ char *guestfs_hexdump (guestfs_h *g, return ctx.ret.dump; /* caller will free */ } +struct zerofree_ctx { + /* This flag is set by the callbacks, so we know we've done + * the callbacks as expected, and in the right sequence. + * 0 = not called, 1 = reply_cb called. + */ + int cb_sequence; + struct guestfs_message_header hdr; + struct guestfs_message_error err; +}; + +static void zerofree_reply_cb (guestfs_h *g, void *data, XDR *xdr) +{ + guestfs_main_loop *ml = guestfs_get_main_loop (g); + struct zerofree_ctx *ctx = (struct zerofree_ctx *) data; + + /* This should definitely not happen. */ + if (ctx->cb_sequence != 0) { + ctx->cb_sequence = 9999; + error (g, "%s: internal error: reply callback called twice", "guestfs_zerofree"); + return; + } + + ml->main_loop_quit (ml, g); + + if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) { + error (g, "%s: failed to parse reply header", "guestfs_zerofree"); + return; + } + if (ctx->hdr.status == GUESTFS_STATUS_ERROR) { + if (!xdr_guestfs_message_error (xdr, &ctx->err)) { + error (g, "%s: failed to parse reply error", "guestfs_zerofree"); + return; + } + goto done; + } + done: + ctx->cb_sequence = 1; +} + +int guestfs_zerofree (guestfs_h *g, + const char *device) +{ + struct guestfs_zerofree_args args; + struct zerofree_ctx ctx; + guestfs_main_loop *ml = guestfs_get_main_loop (g); + int serial; + + if (check_state (g, "guestfs_zerofree") == -1) return -1; + guestfs_set_busy (g); + + memset (&ctx, 0, sizeof ctx); + + args.device = (char *) device; + serial = guestfs__send_sync (g, GUESTFS_PROC_ZEROFREE, + (xdrproc_t) xdr_guestfs_zerofree_args, (char *) &args); + if (serial == -1) { + guestfs_end_busy (g); + return -1; + } + + guestfs__switch_to_receiving (g); + ctx.cb_sequence = 0; + guestfs_set_reply_callback (g, zerofree_reply_cb, &ctx); + (void) ml->main_loop_run (ml, g); + guestfs_set_reply_callback (g, NULL, NULL); + if (ctx.cb_sequence != 1) { + error (g, "%s reply failed, see earlier error messages", "guestfs_zerofree"); + guestfs_end_busy (g); + return -1; + } + + if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_ZEROFREE, serial) == -1) { + guestfs_end_busy (g); + return -1; + } + + if (ctx.hdr.status == GUESTFS_STATUS_ERROR) { + error (g, "%s", ctx.err.error_message); + free (ctx.err.error_message); + guestfs_end_busy (g); + return -1; + } + + guestfs_end_busy (g); + return 0; +} + diff --git a/src/guestfs-actions.h b/src/guestfs-actions.h index 92c1a93..9a4e923 100644 --- a/src/guestfs-actions.h +++ b/src/guestfs-actions.h @@ -139,3 +139,4 @@ extern int guestfs_equal (guestfs_h *handle, const char *file1, const char *file extern char **guestfs_strings (guestfs_h *handle, const char *path); extern char **guestfs_strings_e (guestfs_h *handle, const char *encoding, const char *path); extern char *guestfs_hexdump (guestfs_h *handle, const char *path); +extern int guestfs_zerofree (guestfs_h *handle, const char *device); diff --git a/src/guestfs_protocol.c b/src/guestfs_protocol.c index d53bcff..c505b25 100644 --- a/src/guestfs_protocol.c +++ b/src/guestfs_protocol.c @@ -1614,6 +1614,16 @@ xdr_guestfs_hexdump_ret (XDR *xdrs, guestfs_hexdump_ret *objp) } bool_t +xdr_guestfs_zerofree_args (XDR *xdrs, guestfs_zerofree_args *objp) +{ + register int32_t *buf; + + if (!xdr_string (xdrs, &objp->device, ~0)) + return FALSE; + return TRUE; +} + +bool_t xdr_guestfs_procedure (XDR *xdrs, guestfs_procedure *objp) { register int32_t *buf; diff --git a/src/guestfs_protocol.h b/src/guestfs_protocol.h index 87db39b..a855307 100644 --- a/src/guestfs_protocol.h +++ b/src/guestfs_protocol.h @@ -837,6 +837,11 @@ struct guestfs_hexdump_ret { }; typedef struct guestfs_hexdump_ret guestfs_hexdump_ret; +struct guestfs_zerofree_args { + char *device; +}; +typedef struct guestfs_zerofree_args guestfs_zerofree_args; + enum guestfs_procedure { GUESTFS_PROC_MOUNT = 1, GUESTFS_PROC_SYNC = 2, @@ -934,7 +939,8 @@ enum guestfs_procedure { GUESTFS_PROC_STRINGS = 94, GUESTFS_PROC_STRINGS_E = 95, GUESTFS_PROC_HEXDUMP = 96, - GUESTFS_PROC_NR_PROCS = 96 + 1, + GUESTFS_PROC_ZEROFREE = 97, + GUESTFS_PROC_NR_PROCS = 97 + 1, }; typedef enum guestfs_procedure guestfs_procedure; #define GUESTFS_MESSAGE_MAX 4194304 @@ -1116,6 +1122,7 @@ extern bool_t xdr_guestfs_strings_e_args (XDR *, guestfs_strings_e_args*); extern bool_t xdr_guestfs_strings_e_ret (XDR *, guestfs_strings_e_ret*); extern bool_t xdr_guestfs_hexdump_args (XDR *, guestfs_hexdump_args*); extern bool_t xdr_guestfs_hexdump_ret (XDR *, guestfs_hexdump_ret*); +extern bool_t xdr_guestfs_zerofree_args (XDR *, guestfs_zerofree_args*); extern bool_t xdr_guestfs_procedure (XDR *, guestfs_procedure*); extern bool_t xdr_guestfs_message_direction (XDR *, guestfs_message_direction*); extern bool_t xdr_guestfs_message_status (XDR *, guestfs_message_status*); @@ -1256,6 +1263,7 @@ extern bool_t xdr_guestfs_strings_e_args (); extern bool_t xdr_guestfs_strings_e_ret (); extern bool_t xdr_guestfs_hexdump_args (); extern bool_t xdr_guestfs_hexdump_ret (); +extern bool_t xdr_guestfs_zerofree_args (); extern bool_t xdr_guestfs_procedure (); extern bool_t xdr_guestfs_message_direction (); extern bool_t xdr_guestfs_message_status (); diff --git a/src/guestfs_protocol.x b/src/guestfs_protocol.x index 4226424..f09e5b5 100644 --- a/src/guestfs_protocol.x +++ b/src/guestfs_protocol.x @@ -648,6 +648,10 @@ struct guestfs_hexdump_ret { string dump<>; }; +struct guestfs_zerofree_args { + string device<>; +}; + enum guestfs_procedure { GUESTFS_PROC_MOUNT = 1, GUESTFS_PROC_SYNC = 2, @@ -745,6 +749,7 @@ enum guestfs_procedure { GUESTFS_PROC_STRINGS = 94, GUESTFS_PROC_STRINGS_E = 95, GUESTFS_PROC_HEXDUMP = 96, + GUESTFS_PROC_ZEROFREE = 97, GUESTFS_PROC_NR_PROCS }; diff --git a/tests.c b/tests.c index b1382c0..11a1568 100644 --- a/tests.c +++ b/tests.c @@ -118,6 +118,97 @@ static void no_test_warnings (void) fprintf (stderr, "warning: \"guestfs_get_e2uuid\" has no tests\n"); } +static int test_zerofree_0 (void) +{ + /* TestOutput for zerofree (0) */ + char expected[] = "test file"; + { + char device[] = "/dev/sda"; + device[5] = devchar; + char lines_0[] = ","; + char *lines[] = { + lines_0, + NULL + }; + int r; + suppress_error = 0; + r = guestfs_sfdisk (g, device, 0, 0, 0, lines); + if (r == -1) + return -1; + } + { + char fstype[] = "ext3"; + char device[] = "/dev/sda1"; + device[5] = devchar; + int r; + suppress_error = 0; + r = guestfs_mkfs (g, fstype, device); + if (r == -1) + return -1; + } + { + char device[] = "/dev/sda1"; + device[5] = devchar; + char mountpoint[] = "/"; + int r; + suppress_error = 0; + r = guestfs_mount (g, device, mountpoint); + if (r == -1) + return -1; + } + { + char path[] = "/new"; + char content[] = "test file"; + int r; + suppress_error = 0; + r = guestfs_write_file (g, path, content, 0); + if (r == -1) + return -1; + } + { + char pathordevice[] = "/dev/sda1"; + pathordevice[5] = devchar; + int r; + suppress_error = 0; + r = guestfs_umount (g, pathordevice); + if (r == -1) + return -1; + } + { + char device[] = "/dev/sda1"; + device[5] = devchar; + int r; + suppress_error = 0; + r = guestfs_zerofree (g, device); + if (r == -1) + return -1; + } + { + char device[] = "/dev/sda1"; + device[5] = devchar; + char mountpoint[] = "/"; + int r; + suppress_error = 0; + r = guestfs_mount (g, device, mountpoint); + if (r == -1) + return -1; + } + { + char path[] = "/new"; + char *r; + suppress_error = 0; + r = guestfs_cat (g, path); + if (r == NULL) + return -1; + if (strcmp (r, expected) != 0) { + fprintf (stderr, "test_zerofree_0: expected \"%s\" but got \"%s\"\n", expected, r); + return -1; + } + free (r); + } + return 0; +} + static int test_hexdump_0 (void) { /* InitBasicFS for hexdump (0): create ext2 on /dev/sda1 */ @@ -5101,7 +5192,7 @@ static int test_command_lines_0 (void) free (r); } } else - printf ("%s skippedd (reason: test prerequisite)\n", "test_command_lines_0"); + printf ("%s skipped (reason: test prerequisite)\n", "test_command_lines_0"); return 0; } @@ -5225,7 +5316,7 @@ static int test_command_lines_1 (void) free (r); } } else - printf ("%s skippedd (reason: test prerequisite)\n", "test_command_lines_1"); + printf ("%s skipped (reason: test prerequisite)\n", "test_command_lines_1"); return 0; } @@ -5361,7 +5452,7 @@ static int test_command_lines_2 (void) free (r); } } else - printf ("%s skippedd (reason: test prerequisite)\n", "test_command_lines_2"); + printf ("%s skipped (reason: test prerequisite)\n", "test_command_lines_2"); return 0; } @@ -5497,7 +5588,7 @@ static int test_command_lines_3 (void) free (r); } } else - printf ("%s skippedd (reason: test prerequisite)\n", "test_command_lines_3"); + printf ("%s skipped (reason: test prerequisite)\n", "test_command_lines_3"); return 0; } @@ -5645,7 +5736,7 @@ static int test_command_lines_4 (void) free (r); } } else - printf ("%s skippedd (reason: test prerequisite)\n", "test_command_lines_4"); + printf ("%s skipped (reason: test prerequisite)\n", "test_command_lines_4"); return 0; } @@ -5805,7 +5896,7 @@ static int test_command_lines_5 (void) free (r); } } else - printf ("%s skippedd (reason: test prerequisite)\n", "test_command_lines_5"); + printf ("%s skipped (reason: test prerequisite)\n", "test_command_lines_5"); return 0; } @@ -5917,7 +6008,7 @@ static int test_command_lines_6 (void) free (r); } } else - printf ("%s skippedd (reason: test prerequisite)\n", "test_command_lines_6"); + printf ("%s skipped (reason: test prerequisite)\n", "test_command_lines_6"); return 0; } @@ -6041,7 +6132,7 @@ static int test_command_lines_7 (void) free (r); } } else - printf ("%s skippedd (reason: test prerequisite)\n", "test_command_lines_7"); + printf ("%s skipped (reason: test prerequisite)\n", "test_command_lines_7"); return 0; } @@ -6177,7 +6268,7 @@ static int test_command_lines_8 (void) free (r); } } else - printf ("%s skippedd (reason: test prerequisite)\n", "test_command_lines_8"); + printf ("%s skipped (reason: test prerequisite)\n", "test_command_lines_8"); return 0; } @@ -6313,7 +6404,7 @@ static int test_command_lines_9 (void) free (r); } } else - printf ("%s skippedd (reason: test prerequisite)\n", "test_command_lines_9"); + printf ("%s skipped (reason: test prerequisite)\n", "test_command_lines_9"); return 0; } @@ -6449,7 +6540,7 @@ static int test_command_lines_10 (void) free (r); } } else - printf ("%s skippedd (reason: test prerequisite)\n", "test_command_lines_10"); + printf ("%s skipped (reason: test prerequisite)\n", "test_command_lines_10"); return 0; } @@ -6558,7 +6649,7 @@ static int test_command_0 (void) free (r); } } else - printf ("%s skippedd (reason: test prerequisite)\n", "test_command_0"); + printf ("%s skipped (reason: test prerequisite)\n", "test_command_0"); return 0; } @@ -6667,7 +6758,7 @@ static int test_command_1 (void) free (r); } } else - printf ("%s skippedd (reason: test prerequisite)\n", "test_command_1"); + printf ("%s skipped (reason: test prerequisite)\n", "test_command_1"); return 0; } @@ -6776,7 +6867,7 @@ static int test_command_2 (void) free (r); } } else - printf ("%s skippedd (reason: test prerequisite)\n", "test_command_2"); + printf ("%s skipped (reason: test prerequisite)\n", "test_command_2"); return 0; } @@ -6885,7 +6976,7 @@ static int test_command_3 (void) free (r); } } else - printf ("%s skippedd (reason: test prerequisite)\n", "test_command_3"); + printf ("%s skipped (reason: test prerequisite)\n", "test_command_3"); return 0; } @@ -6994,7 +7085,7 @@ static int test_command_4 (void) free (r); } } else - printf ("%s skippedd (reason: test prerequisite)\n", "test_command_4"); + printf ("%s skipped (reason: test prerequisite)\n", "test_command_4"); return 0; } @@ -7103,7 +7194,7 @@ static int test_command_5 (void) free (r); } } else - printf ("%s skippedd (reason: test prerequisite)\n", "test_command_5"); + printf ("%s skipped (reason: test prerequisite)\n", "test_command_5"); return 0; } @@ -7212,7 +7303,7 @@ static int test_command_6 (void) free (r); } } else - printf ("%s skippedd (reason: test prerequisite)\n", "test_command_6"); + printf ("%s skipped (reason: test prerequisite)\n", "test_command_6"); return 0; } @@ -7321,7 +7412,7 @@ static int test_command_7 (void) free (r); } } else - printf ("%s skippedd (reason: test prerequisite)\n", "test_command_7"); + printf ("%s skipped (reason: test prerequisite)\n", "test_command_7"); return 0; } @@ -7430,7 +7521,7 @@ static int test_command_8 (void) free (r); } } else - printf ("%s skippedd (reason: test prerequisite)\n", "test_command_8"); + printf ("%s skipped (reason: test prerequisite)\n", "test_command_8"); return 0; } @@ -7539,7 +7630,7 @@ static int test_command_9 (void) free (r); } } else - printf ("%s skippedd (reason: test prerequisite)\n", "test_command_9"); + printf ("%s skipped (reason: test prerequisite)\n", "test_command_9"); return 0; } @@ -7648,7 +7739,7 @@ static int test_command_10 (void) free (r); } } else - printf ("%s skippedd (reason: test prerequisite)\n", "test_command_10"); + printf ("%s skipped (reason: test prerequisite)\n", "test_command_10"); return 0; } @@ -7750,7 +7841,7 @@ static int test_command_11 (void) free (r); } } else - printf ("%s skippedd (reason: test prerequisite)\n", "test_command_11"); + printf ("%s skipped (reason: test prerequisite)\n", "test_command_11"); return 0; } @@ -13025,9 +13116,15 @@ int main (int argc, char *argv[]) free (devs[i]); free (devs); - nr_tests = 135; + nr_tests = 136; test_num++; + printf ("%3d/%3d test_zerofree_0\n", test_num, nr_tests); + if (test_zerofree_0 () == -1) { + printf ("test_zerofree_0 FAILED\n"); + failed++; + } + test_num++; printf ("%3d/%3d test_hexdump_0\n", test_num, nr_tests); if (test_hexdump_0 () == -1) { printf ("test_hexdump_0 FAILED\n"); -- 1.8.3.1