static int send_chunk (const guestfs_chunk *chunk) { char buf[GUESTFS_MAX_CHUNK_SIZE + 48]; char lenbuf[4]; XDR xdr; uint32_t len; xdrmem_create (&xdr, buf, sizeof buf, XDR_ENCODE); if (!xdr_guestfs_chunk (&xdr, (guestfs_chunk *) chunk)) { fprintf (stderr, "guestfsd: send_chunk: failed to encode chunk\n"); xdr_destroy (&xdr); return -1; } len = xdr_getpos (&xdr); xdr_destroy (&xdr); xdrmem_create (&xdr, lenbuf, 4, XDR_ENCODE); xdr_u_int (&xdr, &len); xdr_destroy (&xdr); int err = (xwrite (sock, lenbuf, 4) == 0 && xwrite (sock, buf, len) == 0 ? 0 : -1); if (err) { fprintf (stderr, "guestfsd: send_chunk: write failed\n"); exit (EXIT_FAILURE); } return err; }
static int send_file_chunk (guestfs_h *g, int cancel, const char *buf, size_t buflen) { u_int32_t len; int r; guestfs_chunk chunk; XDR xdr; char *msg_out; size_t msg_out_size; /* Allocate the chunk buffer. Don't use the stack to avoid * excessive stack usage and unnecessary copies. */ msg_out = safe_malloc (g, GUESTFS_MAX_CHUNK_SIZE + 4 + 48); xdrmem_create (&xdr, msg_out + 4, GUESTFS_MAX_CHUNK_SIZE + 48, XDR_ENCODE); /* Serialize the chunk. */ chunk.cancel = cancel; chunk.data.data_len = buflen; chunk.data.data_val = (char *) buf; if (!xdr_guestfs_chunk (&xdr, &chunk)) { error (g, _("xdr_guestfs_chunk failed (buf = %p, buflen = %zu)"), buf, buflen); xdr_destroy (&xdr); goto cleanup1; } len = xdr_getpos (&xdr); xdr_destroy (&xdr); /* Reduce the size of the outgoing message buffer to the real length. */ msg_out = safe_realloc (g, msg_out, len + 4); msg_out_size = len + 4; xdrmem_create (&xdr, msg_out, 4, XDR_ENCODE); xdr_uint32_t (&xdr, &len); r = guestfs___send_to_daemon (g, msg_out, msg_out_size); /* Did the daemon send a cancellation message? */ if (r == -2) { debug (g, "got daemon cancellation"); return -2; } if (r == -1) goto cleanup1; free (msg_out); return 0; cleanup1: free (msg_out); return -1; }
/* Returns -1 = error, 0 = EOF, > 0 = more data */ static ssize_t receive_file_data (guestfs_h *g, void **buf_r) { int r; void *buf; uint32_t len; XDR xdr; guestfs_chunk chunk; r = guestfs___recv_from_daemon (g, &len, &buf); if (r == -1) { error (g, _("receive_file_data: parse error in reply callback")); return -1; } if (len == GUESTFS_LAUNCH_FLAG || len == GUESTFS_CANCEL_FLAG) { error (g, _("receive_file_data: unexpected flag received when reading file chunks")); return -1; } memset (&chunk, 0, sizeof chunk); xdrmem_create (&xdr, buf, len, XDR_DECODE); if (!xdr_guestfs_chunk (&xdr, &chunk)) { error (g, _("failed to parse file chunk")); free (buf); return -1; } xdr_destroy (&xdr); /* After decoding, the original buffer is no longer used. */ free (buf); if (chunk.cancel) { 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; } if (chunk.data.data_len == 0) { /* end of transfer */ free (chunk.data.data_val); return 0; } if (buf_r) *buf_r = chunk.data.data_val; else free (chunk.data.data_val); /* else caller frees */ return chunk.data.data_len; }
/** * Receive a chunk of file data. * * Returns C<-1> = error, C<0> = EOF, C<E<gt>0> = more data */ static ssize_t receive_file_data (guestfs_h *g, void **buf_r) { int r; CLEANUP_FREE void *buf = NULL; uint32_t len; XDR xdr; guestfs_chunk chunk; r = guestfs_int_recv_from_daemon (g, &len, &buf); if (r == -1) return -1; if (len == GUESTFS_LAUNCH_FLAG || len == GUESTFS_CANCEL_FLAG) { error (g, _("receive_file_data: unexpected flag received when reading file chunks")); return -1; } memset (&chunk, 0, sizeof chunk); xdrmem_create (&xdr, buf, len, XDR_DECODE); if (!xdr_guestfs_chunk (&xdr, &chunk)) { error (g, _("failed to parse file chunk")); return -1; } xdr_destroy (&xdr); if (chunk.cancel) { if (g->user_cancel) guestfs_int_error_errno (g, EINTR, _("operation cancelled by user")); else error (g, _("file receive cancelled by daemon")); free (chunk.data.data_val); return -1; } if (chunk.data.data_len == 0) { /* end of transfer */ free (chunk.data.data_val); return 0; } if (buf_r) *buf_r = chunk.data.data_val; else free (chunk.data.data_val); /* else caller frees */ return chunk.data.data_len; }
static int send_chunk (const guestfs_chunk *chunk) { const size_t buf_len = GUESTFS_MAX_CHUNK_SIZE + 48; CLEANUP_FREE char *buf = NULL; char lenbuf[4]; XDR xdr; uint32_t len; buf = malloc (buf_len); if (buf == NULL) { perror ("malloc"); return -1; } xdrmem_create (&xdr, buf, buf_len, XDR_ENCODE); if (!xdr_guestfs_chunk (&xdr, (guestfs_chunk *) chunk)) { fprintf (stderr, "guestfsd: send_chunk: failed to encode chunk\n"); xdr_destroy (&xdr); return -1; } len = xdr_getpos (&xdr); xdr_destroy (&xdr); xdrmem_create (&xdr, lenbuf, 4, XDR_ENCODE); xdr_u_int (&xdr, &len); xdr_destroy (&xdr); int err = (xwrite (sock, lenbuf, 4) == 0 && xwrite (sock, buf, len) == 0 ? 0 : -1); if (err) { fprintf (stderr, "guestfsd: send_chunk: write failed\n"); exit (EXIT_FAILURE); } return err; }
static int send_file_chunk (guestfs_h *g, int cancel, const char *buf, size_t buflen) { uint32_t len; ssize_t r; guestfs_chunk chunk; XDR xdr; CLEANUP_FREE char *msg_out = NULL; size_t msg_out_size; /* Allocate the chunk buffer. Don't use the stack to avoid * excessive stack usage and unnecessary copies. */ msg_out = safe_malloc (g, GUESTFS_MAX_CHUNK_SIZE + 4 + 48); xdrmem_create (&xdr, msg_out + 4, GUESTFS_MAX_CHUNK_SIZE + 48, XDR_ENCODE); /* Serialize the chunk. */ chunk.cancel = cancel; chunk.data.data_len = buflen; chunk.data.data_val = (char *) buf; if (!xdr_guestfs_chunk (&xdr, &chunk)) { error (g, _("xdr_guestfs_chunk failed (buf = %p, buflen = %zu)"), buf, buflen); xdr_destroy (&xdr); return -1; } len = xdr_getpos (&xdr); xdr_destroy (&xdr); /* Reduce the size of the outgoing message buffer to the real length. */ msg_out = safe_realloc (g, msg_out, len + 4); msg_out_size = len + 4; xdrmem_create (&xdr, msg_out, 4, XDR_ENCODE); xdr_uint32_t (&xdr, &len); /* Did the daemon send a cancellation message? */ r = check_daemon_socket (g); if (r == -2) { debug (g, "got daemon cancellation"); return -2; } if (r == -1) return -1; if (r == 0) { guestfs_int_unexpected_close_error (g); child_cleanup (g); return -1; } /* Send the chunk. */ r = g->conn->ops->write_data (g, g->conn, msg_out, msg_out_size); if (r == -1) return -1; if (r == 0) { guestfs_int_unexpected_close_error (g); child_cleanup (g); return -1; } return 0; }
/* Receive file chunks, repeatedly calling 'cb'. */ int receive_file (receive_cb cb, void *opaque) { guestfs_chunk chunk; char lenbuf[4]; XDR xdr; int r; uint32_t len; for (;;) { CLEANUP_FREE char *buf = NULL; if (verbose) fprintf (stderr, "guestfsd: receive_file: reading length word\n"); /* Read the length word. */ if (xread (sock, lenbuf, 4) == -1) exit (EXIT_FAILURE); xdrmem_create (&xdr, lenbuf, 4, XDR_DECODE); xdr_u_int (&xdr, &len); xdr_destroy (&xdr); if (len == GUESTFS_CANCEL_FLAG) continue; /* Just ignore it. */ if (len > GUESTFS_MESSAGE_MAX) error (EXIT_FAILURE, 0, "incoming message is too long (%u bytes)", len); buf = malloc (len); if (!buf) { perror ("malloc"); return -1; } if (xread (sock, buf, len) == -1) exit (EXIT_FAILURE); xdrmem_create (&xdr, buf, len, XDR_DECODE); memset (&chunk, 0, sizeof chunk); if (!xdr_guestfs_chunk (&xdr, &chunk)) { xdr_destroy (&xdr); return -1; } xdr_destroy (&xdr); if (verbose) fprintf (stderr, "guestfsd: receive_file: got chunk: cancel = 0x%x, len = %u, buf = %p\n", (unsigned) chunk.cancel, chunk.data.data_len, chunk.data.data_val); if (chunk.cancel != 0 && chunk.cancel != 1) { fprintf (stderr, "guestfsd: receive_file: chunk.cancel != [0|1] ... " "continuing even though we have probably lost synchronization with the library\n"); return -1; } if (chunk.cancel) { if (verbose) fprintf (stderr, "guestfsd: receive_file: received cancellation from library\n"); xdr_free ((xdrproc_t) xdr_guestfs_chunk, (char *) &chunk); return -2; } if (chunk.data.data_len == 0) { if (verbose) fprintf (stderr, "guestfsd: receive_file: end of file, leaving function\n"); xdr_free ((xdrproc_t) xdr_guestfs_chunk, (char *) &chunk); return 0; /* end of file */ } /* Note that the callback can generate progress messages. */ if (cb) r = cb (opaque, chunk.data.data_val, chunk.data.data_len); else r = 0; xdr_free ((xdrproc_t) xdr_guestfs_chunk, (char *) &chunk); if (r == -1) { /* write error */ if (verbose) fprintf (stderr, "guestfsd: receive_file: write error\n"); return -1; } } }