extern int do_drop_caches (int whattodrop);
extern char *do_dmesg (void);
extern int do_ping_daemon (void);
+extern int do_equal (const char *file1, const char *file2);
done: ;
}
+static void equal_stub (XDR *xdr_in)
+{
+ int r;
+ struct guestfs_equal_args args;
+ const char *file1;
+ const char *file2;
+
+ memset (&args, 0, sizeof args);
+
+ if (!xdr_guestfs_equal_args (xdr_in, &args)) {
+ reply_with_error ("%s: daemon failed to decode procedure arguments", "equal");
+ return;
+ }
+ file1 = args.file1;
+ file2 = args.file2;
+
+ r = do_equal (file1, file2);
+ if (r == -1)
+ /* do_equal has already called reply_with_error */
+ goto done;
+
+ struct guestfs_equal_ret ret;
+ ret.equality = r;
+ reply ((xdrproc_t) &xdr_guestfs_equal_ret, (char *) &ret);
+done:
+ xdr_free ((xdrproc_t) xdr_guestfs_equal_args, (char *) &args);
+}
+
void dispatch_incoming_message (XDR *xdr_in)
{
switch (proc_nr) {
case GUESTFS_PROC_PING_DAEMON:
ping_daemon_stub (xdr_in);
break;
+ case GUESTFS_PROC_EQUAL:
+ equal_stub (xdr_in);
+ break;
default:
reply_with_error ("dispatch_incoming_message: unknown procedure number %d", proc_nr);
}
printf ("%-20s %s\n", "dmesg", "return kernel messages");
printf ("%-20s %s\n", "download", "download a file to the local machine");
printf ("%-20s %s\n", "drop-caches", "drop kernel page cache, dentries and inodes");
+ printf ("%-20s %s\n", "equal", "test if two files have equal contents");
printf ("%-20s %s\n", "exists", "test if file or directory exists");
printf ("%-20s %s\n", "file", "determine file type");
printf ("%-20s %s\n", "fsck", "run the filesystem checker");
if (strcasecmp (cmd, "ping_daemon") == 0 || strcasecmp (cmd, "ping-daemon") == 0)
pod2text ("ping-daemon - ping the guest daemon", " ping-daemon\n\nThis is a test probe into the guestfs daemon running inside\nthe qemu subprocess. Calling this function checks that the\ndaemon responds to the ping message, without affecting the daemon\nor attached block device(s) in any other way.");
else
+ if (strcasecmp (cmd, "equal") == 0)
+ pod2text ("equal - test if two files have equal contents", " equal <file1> <file2>\n\nThis compares the two files C<file1> and C<file2> and returns\ntrue if their content is exactly equal, or false otherwise.\n\nThe external L<cmp(1)> program is used for the comparison.");
+ else
display_builtin_command (cmd);
}
return r;
}
+static int run_equal (const char *cmd, int argc, char *argv[])
+{
+ int r;
+ const char *file1;
+ const char *file2;
+ if (argc != 2) {
+ fprintf (stderr, "%s should have 2 parameter(s)\n", cmd);
+ fprintf (stderr, "type 'help %s' for help on %s\n", cmd, cmd);
+ return -1;
+ }
+ file1 = argv[0];
+ file2 = argv[1];
+ r = guestfs_equal (g, file1, file2);
+ if (r == -1) return -1;
+ if (r) printf ("true\n"); else printf ("false\n");
+ return 0;
+}
+
int run_action (const char *cmd, int argc, char *argv[])
{
if (strcasecmp (cmd, "launch") == 0 || strcasecmp (cmd, "run") == 0)
if (strcasecmp (cmd, "ping_daemon") == 0 || strcasecmp (cmd, "ping-daemon") == 0)
return run_ping_daemon (cmd, argc, argv);
else
+ if (strcasecmp (cmd, "equal") == 0)
+ return run_equal (cmd, argc, argv);
+ else
{
fprintf (stderr, "%s: unknown command\n", cmd);
return -1;
"dmesg",
"download",
"drop-caches",
+ "equal",
"exists",
"file",
"fsck",
This automatically calls L<sync(2)> before the operation,
so that the maximum guest memory is freed.
+=head2 equal
+
+ equal file1 file2
+
+This compares the two files C<file1> and C<file2> and returns
+true if their content is exactly equal, or false otherwise.
+
+The external L<cmp(1)> program is used for the comparison.
+
=head2 exists
exists path
This function returns 0 on success or -1 on error.
+=head2 guestfs_equal
+
+ int guestfs_equal (guestfs_h *handle,
+ const char *file1,
+ const char *file2);
+
+This compares the two files C<file1> and C<file2> and returns
+true if their content is exactly equal, or false otherwise.
+
+The external L<cmp(1)> program is used for the comparison.
+
+This function returns a C truth value on success or -1 on error.
+
=head2 guestfs_exists
int guestfs_exists (guestfs_h *handle,
private native void _ping_daemon (long g)
throws LibGuestFSException;
+ /**
+ * test if two files have equal contents
+ *
+ * This compares the two files "file1" and "file2" and
+ * returns true if their content is exactly equal, or false
+ * otherwise.
+ *
+ * The external cmp(1) program is used for the comparison.
+ *
+ * @throws LibGuestFSException
+ */
+ public boolean equal (String file1, String file2)
+ throws LibGuestFSException
+ {
+ if (g == 0)
+ throw new LibGuestFSException ("equal: handle is closed");
+ return _equal (g, file1, file2);
+ }
+ private native boolean _equal (long g, String file1, String file2)
+ throws LibGuestFSException;
+
}
}
}
+JNIEXPORT jboolean JNICALL
+Java_com_redhat_et_libguestfs_GuestFS__1equal
+ (JNIEnv *env, jobject obj, jlong jg, jstring jfile1, jstring jfile2)
+{
+ guestfs_h *g = (guestfs_h *) (long) jg;
+ int r;
+ const char *file1;
+ const char *file2;
+
+ file1 = (*env)->GetStringUTFChars (env, jfile1, NULL);
+ file2 = (*env)->GetStringUTFChars (env, jfile2, NULL);
+ r = guestfs_equal (g, file1, file2);
+ (*env)->ReleaseStringUTFChars (env, jfile1, file1);
+ (*env)->ReleaseStringUTFChars (env, jfile2, file2);
+ if (r == -1) {
+ throw_exception (env, guestfs_last_error (g));
+ return 0;
+ }
+ return (jboolean) r;
+}
+
external drop_caches : t -> int -> unit = "ocaml_guestfs_drop_caches"
external dmesg : t -> string = "ocaml_guestfs_dmesg"
external ping_daemon : t -> unit = "ocaml_guestfs_ping_daemon"
+external equal : t -> string -> string -> bool = "ocaml_guestfs_equal"
val ping_daemon : t -> unit
(** ping the guest daemon *)
+val equal : t -> string -> string -> bool
+(** test if two files have equal contents *)
+
CAMLreturn (rv);
}
+CAMLprim value
+ocaml_guestfs_equal (value gv, value file1v, value file2v)
+{
+ CAMLparam3 (gv, file1v, file2v);
+ CAMLlocal1 (rv);
+
+ guestfs_h *g = Guestfs_val (gv);
+ if (g == NULL)
+ caml_failwith ("equal: used handle after closing it");
+
+ const char *file1 = String_val (file1v);
+ const char *file2 = String_val (file2v);
+ int r;
+
+ caml_enter_blocking_section ();
+ r = guestfs_equal (g, file1, file2);
+ caml_leave_blocking_section ();
+ if (r == -1)
+ ocaml_guestfs_raise_error (g, "equal");
+
+ rv = Val_bool (r);
+ CAMLreturn (rv);
+}
+
if (r == -1)
croak ("ping_daemon: %s", guestfs_last_error (g));
+SV *
+equal (g, file1, file2)
+ guestfs_h *g;
+ char *file1;
+ char *file2;
+PREINIT:
+ int equality;
+ CODE:
+ equality = guestfs_equal (g, file1, file2);
+ if (equality == -1)
+ croak ("equal: %s", guestfs_last_error (g));
+ RETVAL = newSViv (equality);
+ OUTPUT:
+ RETVAL
+
This automatically calls L<sync(2)> before the operation,
so that the maximum guest memory is freed.
+=item $equality = $h->equal ($file1, $file2);
+
+This compares the two files C<file1> and C<file2> and returns
+true if their content is exactly equal, or false otherwise.
+
+The external L<cmp(1)> program is used for the comparison.
+
=item $existsflag = $h->exists ($path);
This returns C<true> if and only if there is a file, directory
return py_r;
}
+static PyObject *
+py_guestfs_equal (PyObject *self, PyObject *args)
+{
+ PyObject *py_g;
+ guestfs_h *g;
+ PyObject *py_r;
+ int r;
+ const char *file1;
+ const char *file2;
+
+ if (!PyArg_ParseTuple (args, (char *) "Oss:guestfs_equal",
+ &py_g, &file1, &file2))
+ return NULL;
+ g = get_handle (py_g);
+
+ r = guestfs_equal (g, file1, file2);
+ if (r == -1) {
+ PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g));
+ return NULL;
+ }
+
+ py_r = PyInt_FromLong ((long) r);
+ return py_r;
+}
+
static PyMethodDef methods[] = {
{ (char *) "create", py_guestfs_create, METH_VARARGS, NULL },
{ (char *) "close", py_guestfs_close, METH_VARARGS, NULL },
{ (char *) "drop_caches", py_guestfs_drop_caches, METH_VARARGS, NULL },
{ (char *) "dmesg", py_guestfs_dmesg, METH_VARARGS, NULL },
{ (char *) "ping_daemon", py_guestfs_ping_daemon, METH_VARARGS, NULL },
+ { (char *) "equal", py_guestfs_equal, METH_VARARGS, NULL },
{ NULL, NULL, 0, NULL }
};
"""
return libguestfsmod.ping_daemon (self._o)
+ def equal (self, file1, file2):
+ u"""This compares the two files "file1" and "file2" and
+ returns true if their content is exactly equal, or false
+ otherwise.
+
+ The external cmp(1) program is used for the comparison.
+ """
+ return libguestfsmod.equal (self._o, file1, file2)
+
return Qnil;
}
+static VALUE ruby_guestfs_equal (VALUE gv, VALUE file1v, VALUE file2v)
+{
+ guestfs_h *g;
+ Data_Get_Struct (gv, guestfs_h, g);
+ if (!g)
+ rb_raise (rb_eArgError, "%s: used handle after closing it", "equal");
+
+ const char *file1 = StringValueCStr (file1v);
+ if (!file1)
+ rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+ "file1", "equal");
+ const char *file2 = StringValueCStr (file2v);
+ if (!file2)
+ rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+ "file2", "equal");
+
+ int r;
+
+ r = guestfs_equal (g, file1, file2);
+ if (r == -1)
+ rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+ return INT2NUM (r);
+}
+
/* Initialize the module. */
void Init__guestfs ()
{
ruby_guestfs_dmesg, 0);
rb_define_method (c_guestfs, "ping_daemon",
ruby_guestfs_ping_daemon, 0);
+ rb_define_method (c_guestfs, "equal",
+ ruby_guestfs_equal, 2);
}
return 0;
}
+struct equal_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;
+ struct guestfs_equal_ret ret;
+};
+
+static void equal_reply_cb (guestfs_h *g, void *data, XDR *xdr)
+{
+ guestfs_main_loop *ml = guestfs_get_main_loop (g);
+ struct equal_ctx *ctx = (struct equal_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_equal");
+ return;
+ }
+
+ ml->main_loop_quit (ml, g);
+
+ if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
+ error (g, "%s: failed to parse reply header", "guestfs_equal");
+ 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_equal");
+ return;
+ }
+ goto done;
+ }
+ if (!xdr_guestfs_equal_ret (xdr, &ctx->ret)) {
+ error (g, "%s: failed to parse reply", "guestfs_equal");
+ return;
+ }
+ done:
+ ctx->cb_sequence = 1;
+}
+
+int guestfs_equal (guestfs_h *g,
+ const char *file1,
+ const char *file2)
+{
+ struct guestfs_equal_args args;
+ struct equal_ctx ctx;
+ guestfs_main_loop *ml = guestfs_get_main_loop (g);
+ int serial;
+
+ if (check_state (g, "guestfs_equal") == -1) return -1;
+ guestfs_set_busy (g);
+
+ memset (&ctx, 0, sizeof ctx);
+
+ args.file1 = (char *) file1;
+ args.file2 = (char *) file2;
+ serial = guestfs__send_sync (g, GUESTFS_PROC_EQUAL,
+ (xdrproc_t) xdr_guestfs_equal_args, (char *) &args);
+ if (serial == -1) {
+ guestfs_set_ready (g);
+ return -1;
+ }
+
+ guestfs__switch_to_receiving (g);
+ ctx.cb_sequence = 0;
+ guestfs_set_reply_callback (g, equal_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_equal");
+ guestfs_set_ready (g);
+ return -1;
+ }
+
+ if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_EQUAL, serial) == -1) {
+ guestfs_set_ready (g);
+ return -1;
+ }
+
+ if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
+ error (g, "%s", ctx.err.error_message);
+ guestfs_set_ready (g);
+ return -1;
+ }
+
+ guestfs_set_ready (g);
+ return ctx.ret.equality;
+}
+
extern int guestfs_drop_caches (guestfs_h *handle, int whattodrop);
extern char *guestfs_dmesg (guestfs_h *handle);
extern int guestfs_ping_daemon (guestfs_h *handle);
+extern int guestfs_equal (guestfs_h *handle, const char *file1, const char *file2);
}
bool_t
+xdr_guestfs_equal_args (XDR *xdrs, guestfs_equal_args *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_string (xdrs, &objp->file1, ~0))
+ return FALSE;
+ if (!xdr_string (xdrs, &objp->file2, ~0))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_guestfs_equal_ret (XDR *xdrs, guestfs_equal_ret *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_bool (xdrs, &objp->equality))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
xdr_guestfs_procedure (XDR *xdrs, guestfs_procedure *objp)
{
register int32_t *buf;
};
typedef struct guestfs_dmesg_ret guestfs_dmesg_ret;
+struct guestfs_equal_args {
+ char *file1;
+ char *file2;
+};
+typedef struct guestfs_equal_args guestfs_equal_args;
+
+struct guestfs_equal_ret {
+ bool_t equality;
+};
+typedef struct guestfs_equal_ret guestfs_equal_ret;
+
enum guestfs_procedure {
GUESTFS_PROC_MOUNT = 1,
GUESTFS_PROC_SYNC = 2,
GUESTFS_PROC_DROP_CACHES = 90,
GUESTFS_PROC_DMESG = 91,
GUESTFS_PROC_PING_DAEMON = 92,
- GUESTFS_PROC_NR_PROCS = 92 + 1,
+ GUESTFS_PROC_EQUAL = 93,
+ GUESTFS_PROC_NR_PROCS = 93 + 1,
};
typedef enum guestfs_procedure guestfs_procedure;
#define GUESTFS_MESSAGE_MAX 4194304
extern bool_t xdr_guestfs_mv_args (XDR *, guestfs_mv_args*);
extern bool_t xdr_guestfs_drop_caches_args (XDR *, guestfs_drop_caches_args*);
extern bool_t xdr_guestfs_dmesg_ret (XDR *, guestfs_dmesg_ret*);
+extern bool_t xdr_guestfs_equal_args (XDR *, guestfs_equal_args*);
+extern bool_t xdr_guestfs_equal_ret (XDR *, guestfs_equal_ret*);
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*);
extern bool_t xdr_guestfs_mv_args ();
extern bool_t xdr_guestfs_drop_caches_args ();
extern bool_t xdr_guestfs_dmesg_ret ();
+extern bool_t xdr_guestfs_equal_args ();
+extern bool_t xdr_guestfs_equal_ret ();
extern bool_t xdr_guestfs_procedure ();
extern bool_t xdr_guestfs_message_direction ();
extern bool_t xdr_guestfs_message_status ();
string kmsgs<>;
};
+struct guestfs_equal_args {
+ string file1<>;
+ string file2<>;
+};
+
+struct guestfs_equal_ret {
+ bool equality;
+};
+
enum guestfs_procedure {
GUESTFS_PROC_MOUNT = 1,
GUESTFS_PROC_SYNC = 2,
GUESTFS_PROC_DROP_CACHES = 90,
GUESTFS_PROC_DMESG = 91,
GUESTFS_PROC_PING_DAEMON = 92,
+ GUESTFS_PROC_EQUAL = 93,
GUESTFS_PROC_NR_PROCS
};
fprintf (stderr, "warning: \"guestfs_get_e2uuid\" has no tests\n");
}
+static int test_equal_0 (void)
+{
+ /* InitBasicFS for equal (0): create ext2 on /dev/sda1 */
+ {
+ int r;
+ suppress_error = 0;
+ r = guestfs_umount_all (g);
+ if (r == -1)
+ return -1;
+ }
+ {
+ int r;
+ suppress_error = 0;
+ r = guestfs_lvm_remove_all (g);
+ if (r == -1)
+ return -1;
+ }
+ {
+ char *lines[] = {
+ ",",
+ NULL
+ };
+ int r;
+ suppress_error = 0;
+ r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines);
+ if (r == -1)
+ return -1;
+ }
+ {
+ int r;
+ suppress_error = 0;
+ r = guestfs_mkfs (g, "ext2", "/dev/sda1");
+ if (r == -1)
+ return -1;
+ }
+ {
+ int r;
+ suppress_error = 0;
+ r = guestfs_mount (g, "/dev/sda1", "/");
+ if (r == -1)
+ return -1;
+ }
+ /* TestOutputTrue for equal (0) */
+ {
+ int r;
+ suppress_error = 0;
+ r = guestfs_write_file (g, "/file1", "contents of a file", 0);
+ if (r == -1)
+ return -1;
+ }
+ {
+ int r;
+ suppress_error = 0;
+ r = guestfs_cp (g, "/file1", "/file2");
+ if (r == -1)
+ return -1;
+ }
+ {
+ int r;
+ suppress_error = 0;
+ r = guestfs_equal (g, "/file1", "/file2");
+ if (r == -1)
+ return -1;
+ if (!r) {
+ fprintf (stderr, "test_equal_0: expected true, got false\n");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int test_equal_1 (void)
+{
+ /* InitBasicFS for equal (1): create ext2 on /dev/sda1 */
+ {
+ int r;
+ suppress_error = 0;
+ r = guestfs_umount_all (g);
+ if (r == -1)
+ return -1;
+ }
+ {
+ int r;
+ suppress_error = 0;
+ r = guestfs_lvm_remove_all (g);
+ if (r == -1)
+ return -1;
+ }
+ {
+ char *lines[] = {
+ ",",
+ NULL
+ };
+ int r;
+ suppress_error = 0;
+ r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines);
+ if (r == -1)
+ return -1;
+ }
+ {
+ int r;
+ suppress_error = 0;
+ r = guestfs_mkfs (g, "ext2", "/dev/sda1");
+ if (r == -1)
+ return -1;
+ }
+ {
+ int r;
+ suppress_error = 0;
+ r = guestfs_mount (g, "/dev/sda1", "/");
+ if (r == -1)
+ return -1;
+ }
+ /* TestOutputFalse for equal (1) */
+ {
+ int r;
+ suppress_error = 0;
+ r = guestfs_write_file (g, "/file1", "contents of a file", 0);
+ if (r == -1)
+ return -1;
+ }
+ {
+ int r;
+ suppress_error = 0;
+ r = guestfs_write_file (g, "/file2", "contents of another file", 0);
+ if (r == -1)
+ return -1;
+ }
+ {
+ int r;
+ suppress_error = 0;
+ r = guestfs_equal (g, "/file1", "/file2");
+ if (r == -1)
+ return -1;
+ if (r) {
+ fprintf (stderr, "test_equal_1: expected false, got true\n");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int test_equal_2 (void)
+{
+ /* InitBasicFS for equal (2): create ext2 on /dev/sda1 */
+ {
+ int r;
+ suppress_error = 0;
+ r = guestfs_umount_all (g);
+ if (r == -1)
+ return -1;
+ }
+ {
+ int r;
+ suppress_error = 0;
+ r = guestfs_lvm_remove_all (g);
+ if (r == -1)
+ return -1;
+ }
+ {
+ char *lines[] = {
+ ",",
+ NULL
+ };
+ int r;
+ suppress_error = 0;
+ r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines);
+ if (r == -1)
+ return -1;
+ }
+ {
+ int r;
+ suppress_error = 0;
+ r = guestfs_mkfs (g, "ext2", "/dev/sda1");
+ if (r == -1)
+ return -1;
+ }
+ {
+ int r;
+ suppress_error = 0;
+ r = guestfs_mount (g, "/dev/sda1", "/");
+ if (r == -1)
+ return -1;
+ }
+ /* TestLastFail for equal (2) */
+ {
+ int r;
+ suppress_error = 1;
+ r = guestfs_equal (g, "/file1", "/file2");
+ if (r != -1)
+ return -1;
+ }
+ return 0;
+}
+
static int test_ping_daemon_0 (void)
{
/* InitEmpty for ping_daemon (0) */
exit (1);
}
- nr_tests = 104;
+ nr_tests = 107;
test_num++;
+ printf ("%3d/%3d test_equal_0\n", test_num, nr_tests);
+ if (test_equal_0 () == -1) {
+ printf ("test_equal_0 FAILED\n");
+ failed++;
+ }
+ test_num++;
+ printf ("%3d/%3d test_equal_1\n", test_num, nr_tests);
+ if (test_equal_1 () == -1) {
+ printf ("test_equal_1 FAILED\n");
+ failed++;
+ }
+ test_num++;
+ printf ("%3d/%3d test_equal_2\n", test_num, nr_tests);
+ if (test_equal_2 () == -1) {
+ printf ("test_equal_2 FAILED\n");
+ failed++;
+ }
+ test_num++;
printf ("%3d/%3d test_ping_daemon_0\n", test_num, nr_tests);
if (test_ping_daemon_0 () == -1) {
printf ("test_ping_daemon_0 FAILED\n");