qrexec-lib/unpack: option to wait for free disk space

Add an option to wait for disk space before extracting a file from qfile
archive. This will allow extracting backup archive using much smaller
temporary space (only enough to hold few chunks, not the whole archive).

Technically, libqubes-rpc-filecopy library got a set_wait_for_space()
function, accepting a margin (in bytes) to be kept free.

QubesOS/qubes-issues#4791
This commit is contained in:
Marek Marczykowski-Górecki 2019-09-03 19:21:50 +02:00
parent 699e10c057
commit 90ae47ec6d
No known key found for this signature in database
GPG Key ID: 063938BA42CFA724
2 changed files with 36 additions and 0 deletions

View File

@ -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); 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_size_limit(unsigned long long new_bytes_limit, unsigned long long new_files_limit);
void set_verbose(int value); 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 */ /* register open fd to /proc/PID/fd of this process */
void set_procfs_fd(int value); void set_procfs_fd(int value);
int write_all(int fd, const void *buf, int size); int write_all(int fd, const void *buf, int size);

View File

@ -3,6 +3,7 @@
#include <fcntl.h> #include <fcntl.h>
#include <sys/time.h> #include <sys/time.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/statvfs.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
@ -18,6 +19,11 @@ unsigned long long files_limit = 0;
unsigned long long total_bytes = 0; unsigned long long total_bytes = 0;
unsigned long long total_files = 0; unsigned long long total_files = 0;
int verbose = 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 use_tmpfile = 0;
int procdir_fd = -1; int procdir_fd = -1;
@ -55,12 +61,33 @@ void set_verbose(int value)
verbose = value; verbose = value;
} }
void set_wait_for_space(unsigned long value)
{
opt_wait_for_space_margin = value;
}
void set_procfs_fd(int value) void set_procfs_fd(int value)
{ {
procdir_fd = value; procdir_fd = value;
use_tmpfile = 1; 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; unsigned long crc32_sum = 0;
int read_all_with_crc(int fd, void *buf, int size) { int read_all_with_crc(int fd, void *buf, int size) {
int ret; int ret;
@ -133,6 +160,10 @@ void process_one_file_reg(struct file_header *untrusted_hdr,
do_exit(EDQUOT, untrusted_name); do_exit(EDQUOT, untrusted_name);
if (bytes_limit && total_bytes > bytes_limit - untrusted_hdr->filelen) if (bytes_limit && total_bytes > bytes_limit - untrusted_hdr->filelen)
do_exit(EDQUOT, untrusted_name); 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; total_bytes += untrusted_hdr->filelen;
ret = copy_file(fdout, 0, untrusted_hdr->filelen, &crc32_sum); ret = copy_file(fdout, 0, untrusted_hdr->filelen, &crc32_sum);
if (ret != COPY_FILE_OK) { if (ret != COPY_FILE_OK) {