- 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 (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 (g, buf, r) == -1)
- return -1;
- }
-
- if (cancel) {
- send_file_cancellation (g);
- return -1;
- }
-
- if (r == -1) {
- perrorf (g, "read: %s", filename);
- send_file_cancellation (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 (g);
- return -1;
- }
-
- return send_file_complete (g);
-}
-
-/* Send a chunk, cancellation or end of file, wait for it to go. */
-static int
-send_file_chunk (guestfs_h *g, int cancel, const char *buf, size_t len)
-{
- void *data;
- guestfs_chunk chunk;
- XDR xdr;
-
- 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;
- }
-
- chunkdatalen = xdr_getpos (&xdr);
- xdr_destroy (&xdr);
-
- len = xdr_getpos (&xdr);
- xdr_destroy (&xdr);
-
- data = safe_realloc (g, data, len);
- g->msg_out = data;
- g->msg_out_size = len;
- g->msg_out_pos = 0;
-
- /* Change the handle to sock_write_event. */
- if (g->main_loop->remove_handle (g->main_loop, g, g->sock_watch) == -1) {
- error (g, "remove_handle failed in dispatch");
- goto cleanup1;
- }
- g->sock_watch =
- g->main_loop->add_handle (g->main_loop, g, g->sock,
- GUESTFS_HANDLE_WRITABLE,
- sock_write_event, NULL);
- if (g->sock_watch == -1) {
- error (g, "add_handle failed in dispatch");
- goto cleanup1;
- }
-
- return 0;
-
- cleanup1:
- free (g->msg_out);
- g->msg_out = NULL;
- g->msg_out_size = 0;
- g->state = READY;
- return -1;
-}
-
-/* Send a chunk of file data. */
-static int
-send_file_data (guestfs_h *g, const char *buf, size_t len)
-{
- return send_file_chunk (g, 0, buf, len);
-}
-
-/* Send a cancellation message. */
-static int
-send_file_cancellation (guestfs_h *g)
-{
- char buf[1];
- return send_file_chunk (g, 1, buf, 0);
-}
-
-/* Send a file complete chunk. */
-static int
-send_file_complete (guestfs_h *g)
-{
- char buf[0];
- return send_file_chunk (g, 0, buf, 0);
-}
-#endif
-
-/* 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)
-{
- 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 (!FD_ISSET (fd, &ml->rset) &&
- !FD_ISSET (fd, &ml->wset) &&
- !FD_ISSET (fd, &ml->xset)) {
- error (g, "fd %d was not registered", fd);
- return -1;
- }
-
- FD_CLR (fd, &ml->rset);
- FD_CLR (fd, &ml->wset);
- FD_CLR (fd, &ml->xset);
-
- if (fd == ml->max_fd) {
- ml->max_fd--;
- ml->handle_cb_data =
- safe_realloc (g, ml->handle_cb_data,
- sizeof (struct select_handle_cb_data) * (ml->max_fd+1));
- }
-
- ml->nr_fds--;
-
- return 0;
-}
-
-static int
-select_add_timeout (guestfs_main_loop *mlv, guestfs_h *g, int interval,
- guestfs_handle_timeout_cb cb, void *data)
-{
- //struct select_main_loop *ml = (struct select_main_loop *) mlv;
-
- abort (); /* XXX not implemented yet */
-}
-
-static int
-select_remove_timeout (guestfs_main_loop *mlv, guestfs_h *g, int timer)
-{
- //struct select_main_loop *ml = (struct select_main_loop *) mlv;
-
- abort (); /* XXX not implemented yet */
-}
-
-/* The 'g' parameter is just used for error reporting. Events
- * for multiple handles can be dispatched by running the main
- * loop.
- */
-static int
-select_main_loop_run (guestfs_main_loop *mlv, guestfs_h *g)
-{
- struct select_main_loop *ml = (struct select_main_loop *) mlv;
- int fd, r, events;
- fd_set rset2, wset2, xset2;
-
- if (ml->is_running) {
- error (g, "select_main_loop_run: this cannot be called recursively");
- return -1;
- }
-
- ml->is_running = 1;
-
- while (ml->is_running) {
- if (ml->nr_fds == 0)
- break;
-
- rset2 = ml->rset;
- wset2 = ml->wset;
- xset2 = ml->xset;
- r = select (ml->max_fd+1, &rset2, &wset2, &xset2, NULL);
- if (r == -1) {
- perrorf (g, "select");
- ml->is_running = 0;
- return -1;
- }
-
- for (fd = 0; r > 0 && fd <= ml->max_fd; ++fd) {
- events = 0;
- if (FD_ISSET (fd, &rset2))
- events |= GUESTFS_HANDLE_READABLE;
- if (FD_ISSET (fd, &wset2))
- events |= GUESTFS_HANDLE_WRITABLE;
- if (FD_ISSET (fd, &xset2))
- events |= GUESTFS_HANDLE_ERROR | GUESTFS_HANDLE_HANGUP;
- if (events) {
- r--;
- ml->handle_cb_data[fd].cb ((guestfs_main_loop *) ml,
- ml->handle_cb_data[fd].g,
- ml->handle_cb_data[fd].data,
- fd, fd, events);
- }
- }
- }
-
- ml->is_running = 0;
- return 0;
-}
-
-static int
-select_main_loop_quit (guestfs_main_loop *mlv, guestfs_h *g)
-{
- struct select_main_loop *ml = (struct select_main_loop *) mlv;
-
- if (!ml->is_running) {
- error (g, "cannot quit, we are not running in a main loop");
- return -1;
- }
-
- ml->is_running = 0;
- return 0;