summaryrefslogtreecommitdiffstats
path: root/src/proto.c
diff options
context:
space:
mode:
authorRichard W.M. Jones <rjones@redhat.com>2011-07-15 10:43:36 +0100
committerRichard W.M. Jones <rjones@redhat.com>2011-07-15 14:11:46 +0100
commit9ec9c97ce2ba46e56b304d3a367c86adc703160d (patch)
tree69c7ea6ab8a6664d95c8573863536f54284931c7 /src/proto.c
parentf173543fd207bdc254a5eb75180d82ef25eacae9 (diff)
downloadlibguestfs-9ec9c97ce2ba46e56b304d3a367c86adc703160d.tar.gz
libguestfs-9ec9c97ce2ba46e56b304d3a367c86adc703160d.tar.xz
libguestfs-9ec9c97ce2ba46e56b304d3a367c86adc703160d.zip
Add user cancellation to the C API.
This allows long transfers (FileIn and FileOut operations) to be cancelled by calling the signal and thread safe guestfs_user_cancel function. Most of this commit consists of a multithreaded program that tests user cancellation of uploads and downloads.
Diffstat (limited to 'src/proto.c')
-rw-r--r--src/proto.c27
1 files changed, 20 insertions, 7 deletions
diff --git a/src/proto.c b/src/proto.c
index d8b10486..be7fbdcf 100644
--- a/src/proto.c
+++ b/src/proto.c
@@ -872,7 +872,6 @@ guestfs___send (guestfs_h *g, int proc_nr,
return -1;
}
-static int cancel = 0; /* XXX Implement file cancellation. */
static int send_file_chunk (guestfs_h *g, int cancel, const char *buf, size_t len);
static int send_file_data (guestfs_h *g, const char *buf, size_t len);
static int send_file_cancellation (guestfs_h *g);
@@ -888,7 +887,9 @@ int
guestfs___send_file (guestfs_h *g, const char *filename)
{
char buf[GUESTFS_MAX_CHUNK_SIZE];
- int fd, r, err;
+ int fd, r = 0, err;
+
+ g->user_cancel = 0;
fd = open (filename, O_RDONLY);
if (fd == -1) {
@@ -898,7 +899,7 @@ guestfs___send_file (guestfs_h *g, const char *filename)
}
/* Send file in chunked encoding. */
- while (!cancel) {
+ while (!g->user_cancel) {
r = read (fd, buf, sizeof buf);
if (r == -1 && (errno == EINTR || errno == EAGAIN))
continue;
@@ -911,13 +912,15 @@ guestfs___send_file (guestfs_h *g, const char *filename)
}
}
- if (cancel) { /* cancel from either end */
+ if (r == -1) {
+ perrorf (g, "read: %s", filename);
send_file_cancellation (g);
return -1;
}
- if (r == -1) {
- perrorf (g, "read: %s", filename);
+ if (g->user_cancel) {
+ error (g, _("operation cancelled by user"));
+ g->last_errnum = EINTR;
send_file_cancellation (g);
return -1;
}
@@ -1116,6 +1119,8 @@ guestfs___recv_file (guestfs_h *g, const char *filename)
void *buf;
int fd, r;
+ g->user_cancel = 0;
+
fd = open (filename, O_WRONLY|O_CREAT|O_TRUNC|O_NOCTTY, 0666);
if (fd == -1) {
perrorf (g, "open: %s", filename);
@@ -1130,6 +1135,9 @@ guestfs___recv_file (guestfs_h *g, const char *filename)
goto cancel;
}
free (buf);
+
+ if (g->user_cancel)
+ goto cancel;
}
if (r == -1) {
@@ -1205,7 +1213,12 @@ receive_file_data (guestfs_h *g, void **buf_r)
free (buf);
if (chunk.cancel) {
- error (g, _("file receive cancelled by daemon"));
+ if (g->user_cancel) {
+ error (g, _("operation cancelled by user"));
+ g->last_errnum = EINTR;
+ }
+ else
+ error (g, _("file receive cancelled by daemon"));
free (chunk.data.data_val);
return -1;
}