-struct receive_file_ctx {
- int count; /* 0 if receive_file_cb not called, or
- * else count number of chunks.
- */
- guestfs_chunk *chunks; /* Array of chunks. */
-};
-
-static void
-free_chunks (struct receive_file_ctx *ctx)
-{
- int i;
-
- for (i = 0; i < ctx->count; ++i)
- free (ctx->chunks[i].data.data_val);
-
- free (ctx->chunks);
-}
-
-static void
-receive_file_cb (guestfs_h *g, void *data, XDR *xdr)
-{
- guestfs_main_loop *ml = guestfs_get_main_loop (g);
- struct receive_file_ctx *ctx = (struct receive_file_ctx *) data;
- guestfs_chunk chunk;
-
- if (ctx->count == -1) /* Parse error occurred previously. */
- return;
-
- ml->main_loop_quit (ml, g);
-
- memset (&chunk, 0, sizeof chunk);
-
- if (!xdr_guestfs_chunk (xdr, &chunk)) {
- error (g, _("failed to parse file chunk"));
- free_chunks (ctx);
- ctx->chunks = NULL;
- ctx->count = -1;
- return;
- }
-
- /* Copy the chunk to the list. */
- ctx->chunks = safe_realloc (g, ctx->chunks,
- sizeof (guestfs_chunk) * (ctx->count+1));
- ctx->chunks[ctx->count] = chunk;
- ctx->count++;
-}
-
-/* Receive a chunk of file data. */
-/* Returns -1 = error, 0 = EOF, 1 = more data */
-static int
-receive_file_data_sync (guestfs_h *g, void **buf, size_t *len_r)
-{
- struct receive_file_ctx ctx;
- guestfs_main_loop *ml = guestfs_get_main_loop (g);
- int i;
- size_t len;
-
- ctx.count = 0;
- ctx.chunks = NULL;
-
- guestfs_set_reply_callback (g, receive_file_cb, &ctx);
- (void) ml->main_loop_run (ml, g);
- guestfs_set_reply_callback (g, NULL, NULL);
-
- if (ctx.count == 0) {
- error (g, _("receive_file_data_sync: reply callback not called\n"));
- return -1;
- }
-
- if (ctx.count == -1) {
- error (g, _("receive_file_data_sync: parse error in reply callback\n"));
- /* callback already freed the chunks */
- return -1;
- }
-
- if (g->verbose)
- fprintf (stderr, "receive_file_data_sync: got %d chunks\n", ctx.count);
-
- /* Process each chunk in the list. */
- if (buf) *buf = NULL; /* Accumulate data in this buffer. */
- len = 0;
-
- for (i = 0; i < ctx.count; ++i) {
- if (ctx.chunks[i].cancel) {
- error (g, _("file receive cancelled by daemon"));
- free_chunks (&ctx);
- if (buf) free (*buf);
- if (len_r) *len_r = 0;
- return -1;
- }
-
- if (ctx.chunks[i].data.data_len == 0) { /* end of transfer */
- free_chunks (&ctx);
- if (len_r) *len_r = len;
- return 0;
- }
-
- if (buf) {
- *buf = safe_realloc (g, *buf, len + ctx.chunks[i].data.data_len);
- memcpy (*buf+len, ctx.chunks[i].data.data_val,
- ctx.chunks[i].data.data_len);
- }
- len += ctx.chunks[i].data.data_len;
- }
-
- if (len_r) *len_r = len;
- free_chunks (&ctx);
- return 1;
-}
-
-/* This is the default main loop implementation, using select(2). */
-
-static int
-select_add_handle (guestfs_main_loop *mlv, guestfs_h *g, int fd, int events,
- guestfs_handle_event_cb cb, void *data)
-{
- struct select_main_loop *ml = (struct select_main_loop *) mlv;
-
- if (fd < 0 || fd >= FD_SETSIZE) {
- error (g, _("fd %d is out of range"), fd);
- return -1;
- }
-
- if ((events & ~(GUESTFS_HANDLE_READABLE |
- GUESTFS_HANDLE_WRITABLE |
- GUESTFS_HANDLE_HANGUP |
- GUESTFS_HANDLE_ERROR)) != 0) {
- error (g, _("set of events (0x%x) contains unknown events"), events);
- return -1;
- }
-
- if (events == 0) {
- error (g, _("set of events is empty"));
- return -1;
- }
-
- if (FD_ISSET (fd, &ml->rset) ||
- FD_ISSET (fd, &ml->wset) ||
- FD_ISSET (fd, &ml->xset)) {
- error (g, _("fd %d is already registered"), fd);
- return -1;
- }
-
- if (cb == NULL) {
- error (g, _("callback is NULL"));
- return -1;
- }
-
- if ((events & GUESTFS_HANDLE_READABLE))
- FD_SET (fd, &ml->rset);
- if ((events & GUESTFS_HANDLE_WRITABLE))
- FD_SET (fd, &ml->wset);
- if ((events & GUESTFS_HANDLE_HANGUP) || (events & GUESTFS_HANDLE_ERROR))
- FD_SET (fd, &ml->xset);
-
- if (fd > ml->max_fd) {
- ml->max_fd = fd;
- ml->handle_cb_data =
- safe_realloc (g, ml->handle_cb_data,
- sizeof (struct select_handle_cb_data) * (ml->max_fd+1));
- }
- ml->handle_cb_data[fd].cb = cb;
- ml->handle_cb_data[fd].g = g;
- ml->handle_cb_data[fd].data = data;
-
- ml->nr_fds++;
-
- /* Any integer >= 0 can be the handle, and this is as good as any ... */
- return fd;
-}
-
-static int
-select_remove_handle (guestfs_main_loop *mlv, guestfs_h *g, int fd)