From: Josjuar Lister <j...@tegosec.com> --- 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