summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJakub Janků <janku.jakub.jj@gmail.com>2017-06-04 22:25:55 +0200
committerVictor Toso <me@victortoso.com>2017-06-30 17:05:52 +0200
commit3760f8618c3131c37fc71281f7321f38bfe2a25f (patch)
tree64c7d7df4b02baf97530abf56a7611c0cef9a376 /src
parentca89a0102cd18d94ee87f0ed4aab568988fdd7c3 (diff)
file-xfer: Check free space before file transfer
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_file_xfer_status() sends VD_AGENT_FILE_XFER_STATUS_ERROR. Client then terminates the transfer. Acked-by: Victor Toso <victortoso@redhat.com>
Diffstat (limited to 'src')
-rw-r--r--src/vdagent/file-xfers.c40
-rw-r--r--src/vdagentd/vdagentd.c7
2 files changed, 47 insertions, 0 deletions
diff --git a/src/vdagent/file-xfers.c b/src/vdagent/file-xfers.c
index fe762d7..af73d87 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,33 @@ 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) {
+ gchar *free_space_str, *file_size_str;
+#if GLIB_CHECK_VERSION(2, 30, 0)
+ free_space_str = g_format_size(free_space);
+ file_size_str = g_format_size(task->file_size);
+#else
+ free_space_str = g_format_size_for_display(free_space);
+ file_size_str = g_format_size_for_display(task->file_size);
+#endif
+ 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);
+
+ 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 a0cee50..5373909 100644
--- a/src/vdagentd/vdagentd.c
+++ b/src/vdagentd/vdagentd.c
@@ -925,6 +925,13 @@ static void agent_read_complete(struct udscs_connection **connp,
case VDAGENTD_FILE_XFER_STATUS:{
/* header->arg1 = file xfer task id, header->arg2 = file xfer status */
switch (header->arg2) {
+ case VD_AGENT_FILE_XFER_STATUS_NOT_ENOUGH_SPACE: {
+ uint64_t free_space = GUINT64_TO_LE(*((uint64_t*)data));
+ send_file_xfer_status(virtio_port, "Not enough free space. Cancelling file-xfer %u",
+ header->arg1, header->arg2,
+ (uint8_t*)&free_space, sizeof(uint64_t));
+ break;
+ }
default:
send_file_xfer_status(virtio_port, NULL, header->arg1, header->arg2, NULL, 0);
}