-int
-guestfs__send_sync (guestfs_h *g, int proc_nr,
- xdrproc_t xdrp, char *args)
-{
- char buffer[GUESTFS_MESSAGE_MAX];
- struct guestfs_message_header hdr;
- XDR xdr;
- unsigned len;
- int serial = g->msg_next_serial++;
- int sent;
- guestfs_main_loop *ml = guestfs_get_main_loop (g);
-
- if (g->state != READY) {
- error (g, "dispatch: state %d != READY", g->state);
- return -1;
- }
-
- /* Serialize the header. */
- hdr.prog = GUESTFS_PROGRAM;
- hdr.vers = GUESTFS_PROTOCOL_VERSION;
- hdr.proc = proc_nr;
- hdr.direction = GUESTFS_DIRECTION_CALL;
- hdr.serial = serial;
- hdr.status = GUESTFS_STATUS_OK;
-
- xdrmem_create (&xdr, buffer, sizeof buffer, XDR_ENCODE);
- if (!xdr_guestfs_message_header (&xdr, &hdr)) {
- error (g, "xdr_guestfs_message_header failed");
- return -1;
- }
-
- /* Serialize the args. If any, because some message types
- * have no parameters.
- */
- if (xdrp) {
- if (!(*xdrp) (&xdr, args)) {
- error (g, "dispatch failed to marshal args");
- return -1;
- }
- }
-
- len = xdr_getpos (&xdr);
- xdr_destroy (&xdr);
-
- /* Allocate the outgoing message buffer. */
- g->msg_out = safe_malloc (g, len + 4);
-
- g->msg_out_size = len + 4;
- g->msg_out_pos = 0;
- g->state = BUSY;
-
- xdrmem_create (&xdr, g->msg_out, 4, XDR_ENCODE);
- if (!xdr_uint32_t (&xdr, &len)) {
- error (g, "xdr_uint32_t failed in dispatch");
- goto cleanup1;
- }
-
- memcpy (g->msg_out + 4, buffer, len);
-
- if (guestfs__switch_to_sending (g) == -1)
- goto cleanup1;
-
- sent = 0;
- guestfs_set_send_callback (g, send_cb, &sent);
- if (ml->main_loop_run (ml, g) == -1)
- goto cleanup1;
- if (sent != 1) {
- error (g, "send failed, see earlier error messages");
- goto cleanup1;
- }
-
- return serial;
-
- cleanup1:
- free (g->msg_out);
- g->msg_out = NULL;
- g->msg_out_size = 0;
- g->state = READY;
- return -1;
-}
-
-static int cancel = 0; /* XXX Implement file cancellation. */
-static int send_file_chunk_sync (guestfs_h *g, int cancel, const char *buf, size_t len);
-static int send_file_data_sync (guestfs_h *g, const char *buf, size_t len);
-static int send_file_cancellation_sync (guestfs_h *g);
-static int send_file_complete_sync (guestfs_h *g);
-
-/* Synchronously send a file. */
-int
-guestfs__send_file_sync (guestfs_h *g, const char *filename)
-{
- char buf[GUESTFS_MAX_CHUNK_SIZE];
- int fd, r;
-
- fd = open (filename, O_RDONLY);
- if (fd == -1) {
- perrorf (g, "open: %s", filename);
- send_file_cancellation_sync (g);
- /* Daemon sees cancellation and won't reply, so caller can
- * just return here.
- */
- return -1;
- }
-
- /* Send file in chunked encoding. */
- while (!cancel && (r = read (fd, buf, sizeof buf)) > 0) {
- if (send_file_data_sync (g, buf, r) == -1)
- return -1;
- }
-
- if (cancel) {
- send_file_cancellation_sync (g);
- return -1;
- }
-
- if (r == -1) {
- perrorf (g, "read: %s", filename);
- send_file_cancellation_sync (g);
- return -1;
- }
-
- /* End of file, but before we send that, we need to close
- * the file and check for errors.
- */
- if (close (fd) == -1) {
- perrorf (g, "close: %s", filename);
- send_file_cancellation_sync (g);
- return -1;
- }
-
- return send_file_complete_sync (g);
-}
-
-/* Send a chunk of file data. */
-static int
-send_file_data_sync (guestfs_h *g, const char *buf, size_t len)
-{
- return send_file_chunk_sync (g, 0, buf, len);
-}
-
-/* Send a cancellation message. */
-static int
-send_file_cancellation_sync (guestfs_h *g)
-{
- char buf[1];
- return send_file_chunk_sync (g, 1, buf, 0);
-}
-
-/* Send a file complete chunk. */
-static int
-send_file_complete_sync (guestfs_h *g)
-{
- char buf[1];
- return send_file_chunk_sync (g, 0, buf, 0);
-}
-
-/* Send a chunk, cancellation or end of file, synchronously (ie. wait
- * for it to go).
- */
-static int
-send_file_chunk_sync (guestfs_h *g, int cancel, const char *buf, size_t len)
-{
- void *data;
- unsigned datalen;
- int sent;
- guestfs_chunk chunk;
- XDR xdr;
- guestfs_main_loop *ml = guestfs_get_main_loop (g);
-
- if (g->state != BUSY) {
- error (g, "send_file_chunk: state %d != READY", g->state);
- return -1;
- }
-
- /* Serialize the chunk. */
- chunk.cancel = cancel;
- chunk.data.data_len = len;
- chunk.data.data_val = (char *) buf;
-
- data = safe_malloc (g, GUESTFS_MAX_CHUNK_SIZE + 48);
- xdrmem_create (&xdr, data, GUESTFS_MAX_CHUNK_SIZE + 48, XDR_ENCODE);
- if (xdr_guestfs_chunk (&xdr, &chunk)) {
- error (g, "xdr_guestfs_chunk failed");
- free (data);
- return -1;
- }
-
- datalen = xdr_getpos (&xdr);
- xdr_destroy (&xdr);
-
- data = safe_realloc (g, data, datalen);
- g->msg_out = data;
- g->msg_out_size = datalen;
- g->msg_out_pos = 0;
-
- if (guestfs__switch_to_sending (g) == -1)
- goto cleanup1;
-
- sent = 0;
- guestfs_set_send_callback (g, send_cb, &sent);
- if (ml->main_loop_run (ml, g) == -1)
- goto cleanup1;
- if (sent != 1) {
- error (g, "send file chunk failed, see earlier error messages");
- goto cleanup1;
- }
-
- return 0;
-
- cleanup1:
- free (g->msg_out);
- g->msg_out = NULL;
- g->msg_out_size = 0;
- g->state = READY;
- return -1;
-}
-
-/* Synchronously receive a file.
- * XXX No way to cancel file receives. We would need to send an
- * error to the daemon and have it see this and stop sending.
- */
-static int receive_file_data_sync (guestfs_h *g, void **buf);
-
-int
-guestfs__receive_file_sync (guestfs_h *g, const char *filename)