[Spice-devel] [PATCH spice-vdagent v4] file-xfer: Check free space before file transfer
Pavel Grunt
pgrunt at redhat.com
Wed May 24 06:38:53 UTC 2017
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
More information about the Spice-devel
mailing list