diff options
-rw-r--r-- | daemon/zero.c | 104 | ||||
-rw-r--r-- | generator/generator_actions.ml | 14 | ||||
-rw-r--r-- | src/MAX_PROC_NR | 2 |
3 files changed, 119 insertions, 1 deletions
diff --git a/daemon/zero.c b/daemon/zero.c index c45088cd..3076a602 100644 --- a/daemon/zero.c +++ b/daemon/zero.c @@ -24,6 +24,7 @@ #include <string.h> #include <fcntl.h> #include <unistd.h> +#include <sys/statvfs.h> #include "daemon.h" #include "actions.h" @@ -226,3 +227,106 @@ do_is_zero_device (const char *device) return 1; } + +static int +random_name (char *p) +{ + int fd; + unsigned char c; + + fd = open ("/dev/urandom", O_RDONLY|O_CLOEXEC); + if (fd == -1) { + reply_with_perror ("/dev/urandom"); + return -1; + } + + while (*p) { + if (*p == 'X') { + if (read (fd, &c, 1) != 1) { + reply_with_perror ("read: /dev/urandom"); + close (fd); + return -1; + } + *p = "0123456789abcdefghijklmnopqrstuvwxyz"[c % 36]; + } + + p++; + } + + close (fd); + return 0; +} + +/* Current implementation is to create a file of all zeroes, then + * delete it. The description of this function is left open in order + * to allow better implementations in future, including + * sparsification. + */ +int +do_zero_free_space (const char *dir) +{ + size_t len = strlen (dir); + char filename[sysroot_len+len+14]; /* sysroot + dir + "/" + 8.3 + "\0" */ + int fd; + unsigned skip = 0; + struct statvfs statbuf; + fsblkcnt_t bfree_initial; + + /* Choose a randomly named 8.3 file. Because of the random name, + * this won't conflict with existing files, and it should be + * compatible with any filesystem type inc. FAT. + */ + snprintf (filename, sysroot_len+len+14, "%s%s/XXXXXXXX.XXX", sysroot, dir); + if (random_name (&filename[sysroot_len+len]) == -1) + return -1; + + if (verbose) + printf ("random filename: %s\n", filename); + + /* Open file and fill with zeroes until we run out of space. */ + fd = open (filename, O_WRONLY|O_CREAT|O_EXCL|O_NOCTTY|O_CLOEXEC, 0600); + if (fd == -1) { + reply_with_perror ("open: %s", filename); + return -1; + } + + /* To estimate progress in this operation, we're going to track + * free blocks in this filesystem down to zero. + */ + if (fstatvfs (fd, &statbuf) == -1) { + reply_with_perror ("fstatvfs"); + close (fd); + return -1; + } + bfree_initial = statbuf.f_bfree; + + for (;;) { + if (write (fd, zero_buf, sizeof zero_buf) == -1) { + if (errno == ENOSPC) /* expected error */ + break; + reply_with_perror ("write: %s", filename); + close (fd); + unlink (filename); + return -1; + } + + skip++; + if ((skip & 256) == 0 && fstatvfs (fd, &statbuf) == 0) + notify_progress (bfree_initial - statbuf.f_bfree, bfree_initial); + } + + /* Make sure the file is completely written to disk. */ + close (fd); /* expect this to give an error, don't check it */ + + sync_disks (); + + notify_progress (bfree_initial, bfree_initial); + + /* Remove the file. */ + if (unlink (filename) == -1) { + reply_with_perror ("unlink: %s", filename); + return -1; + } + + return 0; +} diff --git a/generator/generator_actions.ml b/generator/generator_actions.ml index 4c6e704b..4b4e5ffe 100644 --- a/generator/generator_actions.ml +++ b/generator/generator_actions.ml @@ -6748,6 +6748,20 @@ On NTFS filesystems, labels are limited to 128 unicode characters. To read the label on a filesystem, call C<guestfs_vfs_label>."); + ("zero_free_space", (RErr, [Pathname "directory"], []), 311, [Progress], + [InitScratchFS, Always, TestRun ( + [["zero_free_space"; "/"]])], + "zero free space in a filesystem", + "\ +Zero the free space in the filesystem mounted on C<directory>. +The filesystem must be mounted read-write. + +The filesystem contents are not affected, but any free space +in the filesystem is freed. + +In future (but not currently) these zeroed blocks will be +\"sparsified\" - that is, given back to the host."); + ] let all_functions = non_daemon_functions @ daemon_functions diff --git a/src/MAX_PROC_NR b/src/MAX_PROC_NR index 54ea97e9..b661fff6 100644 --- a/src/MAX_PROC_NR +++ b/src/MAX_PROC_NR @@ -1 +1 @@ -310 +311 |