From: Josjuar Lister <[email protected]>
---
src/shred.c | 111 +++++++++++++++++++++++++++++++++++++++++++++-------
1 file changed, 97 insertions(+), 14 deletions(-)
diff --git a/src/shred.c b/src/shred.c
index 03a260243..c824fc495 100644
--- a/src/shred.c
+++ b/src/shred.c
@@ -128,6 +128,7 @@ static enum remove_method const remove_methods[] =
struct Options
{
+ bool recursive; /* -r flag: shred files and directories recursively */
bool force; /* -f flag: chmod files if necessary */
size_t n_iterations; /* -n flag: Number of iterations */
off_t size; /* -s flag: size of file */
@@ -179,6 +180,7 @@ If FILE is -, shred standard output.\n\
emit_mandatory_arg_note ();
printf (_("\
+ -r, --recursive shred files and directories recursively\n\
-f, --force change permissions to allow writing if necessary\n\
-n, --iterations=N overwrite N times instead of the default (%d)\n\
--random-source=FILE get random bytes from FILE\n\
@@ -1035,6 +1037,7 @@ incname (char *name, size_t len)
static bool
wipename (char *oldname, char const *qoldname, struct Options const *flags)
{
+ printf("wipename\n");
char *newname = xstrdup (oldname);
char *base = last_component (newname);
char *dir = dir_name (newname);
@@ -1079,13 +1082,28 @@ wipename (char *oldname, char const *qoldname, struct
Options const *flags)
}
}
- if (unlink (oldname) != 0)
+ struct stat statbuf;
+ if (stat(oldname, &statbuf) == 0 && S_ISDIR(statbuf.st_mode))
{
- error (0, errno, _("%s: failed to remove"), qoldname);
- ok = false;
+ if (rmdir(oldname) != 0)
+ {
+ error(0, errno, _("%s: failed to remove directory"), qoldname);
+ ok = false;
+ }
+ else if (flags->verbose)
+ error(0, 0, _("%s: removed directory"), qoldname);
}
- else if (flags->verbose)
- error (0, 0, _("%s: removed"), qoldname);
+ else
+ {
+ if (unlink (oldname) != 0)
+ {
+ error (0, errno, _("%s: failed to remove"), qoldname);
+ ok = false;
+ }
+ else if (flags->verbose)
+ error (0, 0, _("%s: removed"), qoldname);
+ }
+
if (0 <= dir_fd)
{
if (dosync (dir_fd, qdir) != 0)
@@ -1138,11 +1156,73 @@ wipefile (char *name, char const *qname,
error (0, errno, _("%s: failed to close"), qname);
ok = false;
}
+ printf("remove_file: %u, Ok: %i\n", flags->remove_file, ok);
if (ok && flags->remove_file)
ok = wipename (name, qname, flags);
return ok;
}
+/* Wrapper for handling files simplifies the recursive function */
+static bool
+handle_file (char *name, struct randint_source *s, struct Options const
*flags, bool ok)
+{
+ char *qname = xstrdup (quotef (name));
+ if (STREQ (name, "-"))
+ {
+ ok &= wipefd (STDOUT_FILENO, qname, s, flags);
+ }
+ else
+ {
+ /* Plain filename - Note that this overwrites *argv! */
+ ok &= wipefile (name, qname, s, flags);
+ }
+ free (qname);
+ return ok;
+}
+
+
+/* Directory wiping */
+static bool
+wipe_directory (char *name, struct randint_source *s, struct Options const
*flags, bool ok)
+{
+ DIR *dir;
+ struct dirent *entry;
+ struct stat statbuf;
+ char path[PATH_MAX];
+
+ if (!(dir = opendir(name)))
+ {
+ error (0, errno, _("cannot open directory %s"), name);
+ return false;
+ }
+
+ while ((entry = readdir(dir)) != nullptr)
+ {
+ if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
+ continue;
+
+ snprintf(path, sizeof(path), "%s/%s", name, entry->d_name);
+ if (lstat(path, &statbuf) == -1)
+ {
+ error (0, errno, _("cannot stat %s"), path);
+ continue;
+ }
+
+ if (S_ISDIR(statbuf.st_mode))
+ {
+ if (!wipe_directory(path, s, flags, ok))
+ return false;
+ }
+ else
+ {
+ handle_file(path, s, flags, ok);
+ }
+ }
+ if (flags->remove_file)
+ ok &= wipename(name, name, flags);
+ closedir(dir);
+ return ok;
+}
/* Buffers for random data. */
static struct randint_source *randint_source;
@@ -1168,7 +1248,6 @@ main (int argc, char **argv)
int i;
char const *random_source = nullptr;
- initialize_main (&argc, &argv);
set_program_name (argv[0]);
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
@@ -1179,10 +1258,14 @@ main (int argc, char **argv)
flags.n_iterations = DEFAULT_PASSES;
flags.size = -1;
- while ((c = getopt_long (argc, argv, "fn:s:uvxz", long_opts, nullptr)) != -1)
+ while ((c = getopt_long (argc, argv, "rfn:s:uvxz", long_opts, nullptr)) !=
-1)
{
switch (c)
{
+ case 'r':
+ flags.recursive = true;
+ flags.remove_file = remove_wipesync;
+ break;
case 'f':
flags.force = true;
break;
@@ -1249,21 +1332,21 @@ main (int argc, char **argv)
quotef (random_source ? random_source : "getrandom"));
atexit (clear_random_data);
+ struct stat statbuf;
for (i = 0; i < n_files; i++)
{
- char *qname = xstrdup (quotef (file[i]));
- if (STREQ (file[i], "-"))
+ if (stat(file[i], &statbuf) == 0 && S_ISDIR(statbuf.st_mode))
{
- ok &= wipefd (STDOUT_FILENO, qname, randint_source, &flags);
+ if (! ok){
+ continue;
+ }
+ ok &= wipe_directory (file[i], randint_source, &flags, ok);
}
else
{
- /* Plain filename - Note that this overwrites *argv! */
- ok &= wipefile (file[i], qname, randint_source, &flags);
+ ok &= handle_file (file[i], randint_source, &flags, ok);
}
- free (qname);
}
-
return ok ? EXIT_SUCCESS : EXIT_FAILURE;
}
/*
--
2.39.5