diff --git a/debian/libqubes-rpc-filecopy2.shlibs b/debian/libqubes-rpc-filecopy2.shlibs index a81305d..96667b3 100644 --- a/debian/libqubes-rpc-filecopy2.shlibs +++ b/debian/libqubes-rpc-filecopy2.shlibs @@ -1 +1 @@ -libqubes-rpc-filecopy 2 libqubes-rpc-filecopy2 (>= 3.1.3) +libqubes-rpc-filecopy 2 libqubes-rpc-filecopy2 (>= 4.1.3) diff --git a/qrexec-lib/libqubes-rpc-filecopy.h b/qrexec-lib/libqubes-rpc-filecopy.h index 2b18b39..bbc8e9b 100644 --- a/qrexec-lib/libqubes-rpc-filecopy.h +++ b/qrexec-lib/libqubes-rpc-filecopy.h @@ -74,6 +74,11 @@ int copy_file(int outfd, int infd, long long size, unsigned long *crc32); const char *copy_file_status_to_str(int status); void set_size_limit(unsigned long long new_bytes_limit, unsigned long long new_files_limit); void set_verbose(int value); +/* + * Delay extracting a file if there is no enough space for it - wait for space + * for this file, plus a given margin. + */ +void set_wait_for_space(unsigned long margin); /* register open fd to /proc/PID/fd of this process */ void set_procfs_fd(int value); int write_all(int fd, const void *buf, int size); diff --git a/qrexec-lib/unpack.c b/qrexec-lib/unpack.c index 62ccd5b..a0f02f1 100644 --- a/qrexec-lib/unpack.c +++ b/qrexec-lib/unpack.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -18,6 +19,11 @@ unsigned long long files_limit = 0; unsigned long long total_bytes = 0; unsigned long long total_files = 0; int verbose = 0; +/* + * If positive, wait for disk space before extracting a file, + * keeping this much extra space (in bytes). + */ +unsigned long opt_wait_for_space_margin; int use_tmpfile = 0; int procdir_fd = -1; @@ -51,12 +57,33 @@ void set_verbose(int value) verbose = value; } +void set_wait_for_space(unsigned long value) +{ + opt_wait_for_space_margin = value; +} + void set_procfs_fd(int value) { procdir_fd = value; use_tmpfile = 1; } +int wait_for_space(int fd, unsigned long how_much) { + int counter = 0; + struct statvfs fs_space; + do { + if (fstatvfs(fd, &fs_space) == -1) { + perror("fstatvfs"); + return -1; + } + // TODO: timeout? + if (counter > 0) + usleep(1000000); + counter++; + } while (fs_space.f_bsize * fs_space.f_bavail < how_much); + return 0; +} + unsigned long crc32_sum = 0; int read_all_with_crc(int fd, void *buf, int size) { int ret; @@ -129,6 +156,10 @@ void process_one_file_reg(struct file_header *untrusted_hdr, do_exit(EDQUOT, untrusted_name); if (bytes_limit && total_bytes > bytes_limit - untrusted_hdr->filelen) do_exit(EDQUOT, untrusted_name); + if (opt_wait_for_space_margin) { + wait_for_space(fdout, + untrusted_hdr->filelen + opt_wait_for_space_margin); + } total_bytes += untrusted_hdr->filelen; ret = copy_file(fdout, 0, untrusted_hdr->filelen, &crc32_sum); if (ret != COPY_FILE_OK) {