Hi Jakub, On Sun, 2017-05-21 at 15:19 +0200, Jakub Janků wrote: > Add function get_free_space_available that retrieves amount of free > space in the given directory. The statvfs may fail even when there's > enough free space (e.g. when not supported by system), in this case > return G_MAXUINT64 so that the transfer isn't terminated > groundlessly. > > When the file is too big, send VDAgentFileXferStatusMessage with > result VD_AGENT_FILE_XFER_STATUS_NOT_ENOUGH_SPACE and amount of free > space available, if the result isn't supported by client, send > VD_AGENT_FILE_XFER_STATUS_ERROR. Client then terminates the > transfer. > > Change send_file_xfer_status() to support sending file xfer status > messages with additional (error) data, can be used for reporting > more file xfer errors. > --- > src/vdagent/file-xfers.c | 39 ++++++++++++++++++++++++++ > src/vdagentd/vdagentd.c | 71 ++++++++++++++++++++++++++++++++----- > ----------- > 2 files changed, 86 insertions(+), 24 deletions(-) > > diff --git a/src/vdagent/file-xfers.c b/src/vdagent/file-xfers.c > index b3937a4..3510760 100644 > --- a/src/vdagent/file-xfers.c > +++ b/src/vdagent/file-xfers.c > @@ -32,6 +32,7 @@ > #include <fcntl.h> > #include <errno.h> > #include <sys/stat.h> > +#include <sys/statvfs.h> > #include <sys/types.h> > #include <spice/vd_agent.h> > #include <glib.h> > @@ -168,6 +169,17 @@ error: > return NULL; > } > > +static uint64_t get_free_space_available(const char *path) > +{ > + struct statvfs stat; > + if (statvfs(path, &stat) != 0) { > + syslog(LOG_WARNING, "file-xfer: failed to get free space, > statvfs error: %s", > + strerror(errno)); > + return G_MAXUINT64; > + } > + return stat.f_bsize * stat.f_bavail; > +} > + > void vdagent_file_xfers_start(struct vdagent_file_xfers *xfers, > VDAgentFileXferStartMessage *msg) > { > @@ -175,6 +187,7 @@ void vdagent_file_xfers_start(struct > vdagent_file_xfers *xfers, > char *dir = NULL, *path = NULL, *file_path = NULL; > struct stat st; > int i; > + uint64_t free_space; > > g_return_if_fail(xfers != NULL); > > @@ -193,6 +206,32 @@ void vdagent_file_xfers_start(struct > vdagent_file_xfers *xfers, > > file_path = g_build_filename(xfers->save_dir, task->file_name, > NULL); > > + free_space = get_free_space_available(xfers->save_dir); > + if (task->file_size > free_space) { > + if (GLIB_CHECK_VERSION(2, 30, 0)) { it should be checked at compile time: #if GLIB_CHECK_VERSION(2, 30, 0) > + gchar *free_space_str = g_format_size(free_space); > + gchar *file_size_str = g_format_size(task->file_size); > + syslog(LOG_ERR, "file-xfer: not enough free space (%s > to copy, %s free)", > + file_size_str, free_space_str); > + g_free(free_space_str); > + g_free(file_size_str); #else > + } else { > + syslog(LOG_ERR, "file-xfer: not enough free space (%lu > B to copy, %lu B free)", > + task->file_size, free_space); > + } #endif > + > + udscs_write(xfers->vdagentd, > + VDAGENTD_FILE_XFER_STATUS, > + msg->id, > + VD_AGENT_FILE_XFER_STATUS_NOT_ENOUGH_SPACE, > + (uint8_t *)&free_space, > + sizeof(free_space)); > + vdagent_file_xfer_task_free(task); > + g_free(file_path); > + g_free(dir); > + return; > + } > + > dir = g_path_get_dirname(file_path); > if (g_mkdir_with_parents(dir, S_IRWXU) == -1) { > syslog(LOG_ERR, "file-xfer: Failed to create dir %s", dir); > diff --git a/src/vdagentd/vdagentd.c b/src/vdagentd/vdagentd.c > index f3ac606..7664142 100644 > --- a/src/vdagentd/vdagentd.c > +++ b/src/vdagentd/vdagentd.c > @@ -301,20 +301,38 @@ static void do_client_clipboard(struct > vdagent_virtio_port *vport, > data, size); > } > > -/* To be used by vdagentd for failures in file-xfer such as when > file-xfer was > - * cancelled or an error happened */ > +/* Send file-xfer status to the client. In the case status is an > error, > + * optional data for the client and log message may be specified. > */ > static void send_file_xfer_status(struct vdagent_virtio_port > *vport, > - const char *msg, uint32_t id, > uint32_t xfer_status) > + const char *msg, uint32_t id, > uint32_t xfer_status, > + uint8_t *data, uint32_t the function is not supposed to change 'data', declare it as const > data_size) > { > - VDAgentFileXferStatusMessage status = { > - .id = GUINT32_TO_LE(id), > - .result = GUINT32_TO_LE(xfer_status), > - }; > - syslog(LOG_WARNING, msg, id); > + VDAgentFileXferStatusMessage *status; > + > + /* Replace new detailed errors with older generic > VD_AGENT_FILE_XFER_STATUS_ERROR > + * when not supported by client */ > + if (xfer_status > VD_AGENT_FILE_XFER_STATUS_SUCCESS && > + !VD_AGENT_HAS_CAPABILITY(capabilities, capabilities_size, > + VD_AGENT_CAP_FILE_XFER_DETAILED_ERR > ORS)) { > + xfer_status = VD_AGENT_FILE_XFER_STATUS_ERROR; > + data_size = 0; > + } > + > + status = malloc(sizeof(*status) + data_size); > + status->id = GUINT32_TO_LE(id); > + status->result = GUINT32_TO_LE(xfer_status); > + if (data) > + memcpy(status->data, data, data_size); > + > + if (msg) > + syslog(LOG_WARNING, "file-xfer %u: %s", id, msg); > + > if (vport) > vdagent_virtio_port_write(vport, VDP_CLIENT_PORT, > VD_AGENT_FILE_XFER_STATUS, 0, > - (uint8_t *)&status, > sizeof(status)); > + (uint8_t *)status, > sizeof(*status) + data_size); > + > + free(status); > } > > static void do_client_file_xfer(struct vdagent_virtio_port *vport, > @@ -330,15 +348,15 @@ static void do_client_file_xfer(struct > vdagent_virtio_port *vport, > if (!active_session_conn) { > send_file_xfer_status(vport, > "Could not find an agent connection belonging to the > " > - "active session, cancelling client file-xfer request > %u", > - s->id, VD_AGENT_FILE_XFER_STATUS_CANCELLED); > + "active session, cancelling file-xfer", > + s->id, VD_AGENT_FILE_XFER_STATUS_CANCELLED, NULL, > 0); > return; > } else if (session_info_session_is_locked(session_info)) { > syslog(LOG_DEBUG, "Session is locked, skipping file- > xfer-start"); > send_file_xfer_status(vport, > "User's session is locked and cannot start file > transfer. " > - "Cancelling client file-xfer request %u", > - s->id, VD_AGENT_FILE_XFER_STATUS_ERROR); > + "Cancelling file-xfer", > + s->id, VD_AGENT_FILE_XFER_STATUS_ERROR, NULL, 0); > return; > } > udscs_write(active_session_conn, VDAGENTD_FILE_XFER_START, > 0, 0, > @@ -808,9 +826,9 @@ static gboolean remove_active_xfers(gpointer > key, gpointer value, gpointer conn) > { > if (value == conn) { > send_file_xfer_status(virtio_port, > - "Agent disc; cancelling file-xfer > %u", > + "Agent disc; cancelling file-xfer", > GPOINTER_TO_UINT(key), > - VD_AGENT_FILE_XFER_STATUS_CANCELLED); > + VD_AGENT_FILE_XFER_STATUS_CANCELLED, > NULL, 0); > return 1; > } else > return 0; > @@ -903,17 +921,22 @@ static void agent_read_complete(struct > udscs_connection **connp, > } > break; > case VDAGENTD_FILE_XFER_STATUS:{ > - VDAgentFileXferStatusMessage status; > - status.id = GUINT32_TO_LE(header->arg1); > - status.result = GUINT32_TO_LE(header->arg2); > - vdagent_virtio_port_write(virtio_port, VDP_CLIENT_PORT, > - VD_AGENT_FILE_XFER_STATUS, 0, > - (uint8_t *)&status, > sizeof(status)); > - if (status.result == > VD_AGENT_FILE_XFER_STATUS_CAN_SEND_DATA) > - g_hash_table_insert(active_xfers, > GUINT_TO_POINTER(status.id), > + /* header->arg1 = file xfer task id, header->arg2 = file > xfer status */ > + switch (header->arg2) { > + case VD_AGENT_FILE_XFER_STATUS_NOT_ENOUGH_SPACE: > + send_file_xfer_status(virtio_port, "Not enough free > space. Cancelling file-xfer", > + header->arg1, header->arg2, > data, sizeof(uint64_t)); > + break; > + default: > + send_file_xfer_status(virtio_port, NULL, header- > >arg1, header->arg2, NULL, 0); > + } > + > + if (header->arg2 == > VD_AGENT_FILE_XFER_STATUS_CAN_SEND_DATA) > + g_hash_table_insert(active_xfers, > GUINT_TO_POINTER(GUINT32_TO_LE(header->arg1)), > *connp); > else > - g_hash_table_remove(active_xfers, > GUINT_TO_POINTER(status.id)); > + g_hash_table_remove(active_xfers, > GUINT_TO_POINTER(GUINT32_TO_LE(header->arg1))); > + extra line > break; > } > I'd split the string changes to a different patch Thanks, Pavel _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/spice-devel