summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorRichard W.M. Jones <rjones@redhat.com>2011-03-18 18:27:21 +0000
committerRichard W.M. Jones <rjones@redhat.com>2011-03-21 11:36:13 +0000
commit56bbd763134fa40c3f52799660fed83c325de36c (patch)
treeccf0e8c40ba15aa0fe47bd09dc33f6601a4c4912 /src
parent821083b1c46005cfeebf384e81be812f6b0cc74b (diff)
downloadlibguestfs-56bbd763134fa40c3f52799660fed83c325de36c.tar.gz
libguestfs-56bbd763134fa40c3f52799660fed83c325de36c.tar.xz
libguestfs-56bbd763134fa40c3f52799660fed83c325de36c.zip
proto: Fix both-ends-cancel case.
In the case where both ends cancel at the same time (eg. both ends realize there are errors before or during the transfer), previously we skipped sending back an error from the daemon, on the spurious basis that the library would not need it (the library is cancelling because of its own error). However this is wrong: we should always send back an error message from the daemon in order to preserve synchronization of the protocol. A simple test case is: $ guestfish -N fs -m /dev/sda1 upload nosuchfile / libguestfs: error: open: nosuchfile: No such file or directory libguestfs: error: unexpected procedure number (66/282) (Notice two things: there are errors at both ends, and the loss of synchronization). After applying this commit, the loss of synchronization does not occur and we just see the library error: $ guestfish -N fs -m /dev/sda1 upload nosuchfile / libguestfs: error: open: nosuchfile: No such file or directory The choice of displaying the library or the daemon error is fairly arbitrary in this case -- it would be valid to display either or even to combine them into one error. Displaying the library error only makes the code considerably simpler. This commit also (re-)enables a test for this case. Cherry picked and rebased from commit f4d996fd26762053d68f46de5790aae893f03d38.
Diffstat (limited to 'src')
-rw-r--r--src/guestfs-internal.h1
-rw-r--r--src/proto.c31
2 files changed, 29 insertions, 3 deletions
diff --git a/src/guestfs-internal.h b/src/guestfs-internal.h
index bb682984..8ee0508b 100644
--- a/src/guestfs-internal.h
+++ b/src/guestfs-internal.h
@@ -252,6 +252,7 @@ extern int guestfs___set_busy (guestfs_h *g);
extern int guestfs___end_busy (guestfs_h *g);
extern int guestfs___send (guestfs_h *g, int proc_nr, uint64_t progress_hint, uint64_t optargs_bitmask, xdrproc_t xdrp, char *args);
extern int guestfs___recv (guestfs_h *g, const char *fn, struct guestfs_message_header *hdr, struct guestfs_message_error *err, xdrproc_t xdrp, char *ret);
+extern int guestfs___recv_discard (guestfs_h *g, const char *fn);
extern int guestfs___send_file (guestfs_h *g, const char *filename);
extern int guestfs___recv_file (guestfs_h *g, const char *filename);
extern int guestfs___send_to_daemon (guestfs_h *g, const void *v_buf, size_t n);
diff --git a/src/proto.c b/src/proto.c
index d677c6ec..125c126b 100644
--- a/src/proto.c
+++ b/src/proto.c
@@ -804,9 +804,6 @@ guestfs___send_file (guestfs_h *g, const char *filename)
if (fd == -1) {
perrorf (g, "open: %s", filename);
send_file_cancellation (g);
- /* Daemon sees cancellation and won't reply, so caller can
- * just return here.
- */
return -1;
}
@@ -991,6 +988,34 @@ guestfs___recv (guestfs_h *g, const char *fn,
return 0;
}
+/* Same as guestfs___recv, but it discards the reply message. */
+int
+guestfs___recv_discard (guestfs_h *g, const char *fn)
+{
+ void *buf;
+ uint32_t size;
+ int r;
+
+ again:
+ r = guestfs___recv_from_daemon (g, &size, &buf);
+ if (r == -1)
+ return -1;
+
+ /* This can happen if a cancellation happens right at the end
+ * of us sending a FileIn parameter to the daemon. Discard. The
+ * daemon should send us an error message next.
+ */
+ if (size == GUESTFS_CANCEL_FLAG)
+ goto again;
+
+ if (size == GUESTFS_LAUNCH_FLAG) {
+ error (g, "%s: received unexpected launch flag from daemon when expecting reply", fn);
+ return -1;
+ }
+
+ return 0;
+}
+
/* Receive a file. */
/* Returns -1 = error, 0 = EOF, > 0 = more data */