aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--toys/other/shred.c104
1 files changed, 104 insertions, 0 deletions
diff --git a/toys/other/shred.c b/toys/other/shred.c
new file mode 100644
index 00000000..07d62c3d
--- /dev/null
+++ b/toys/other/shred.c
@@ -0,0 +1,104 @@
+/* shred.c - Overwrite a file to securely delete
+ *
+ * Copyright 2014 Rob Landley <rob@landley.net>
+ *
+ * No standard
+
+USE_SHRED(NEWTOY(shred, "<1zxus#<1n#<1o#<0f", TOYFLAG_USR|TOYFLAG_BIN))
+
+config SHRED
+ bool "shred"
+ default n
+ help
+ usage: shred [-fuz] [-n COUNT] [-s SIZE] FILE...
+
+ Securely delete a file by overwriting its contents with random data.
+
+ -f Force (chmod if necessary)
+ -n COUNT Random overwrite iterations (default 1)
+ -o OFFSET Start at OFFSET
+ -s SIZE Use SIZE instead of detecting file size
+ -u unlink (actually delete file when done)
+ -x Use exact size (default without -s rounds up to next 4k)
+ -z zero at end
+
+ Note: data journaling filesystems render this command useless, you must
+ overwrite all free space (fill up disk) to erase old data on those.
+*/
+
+#define FOR_shred
+#include "toys.h"
+
+GLOBALS(
+ long offset;
+ long iterations;
+ long size;
+
+ int ufd;
+)
+
+void shred_main(void)
+{
+ char **try;
+
+ if (!(toys.optflags & FLAG_n)) TT.iterations++;
+ TT.ufd = xopen("/dev/urandom", O_RDONLY);
+
+ // We don't use loopfiles() here because "-" isn't stdin, and want to
+ // respond to files we can't open via chmod.
+
+ for (try = toys.optargs; *try; try++) {
+ off_t pos = 0, len = TT.size;
+ int fd = open(*try, O_RDWR), iter = 0, throw;
+
+ // do -f chmod if necessary
+ if (fd == -1 && (toys.optflags & FLAG_f)) {
+ chmod(*try, 0600);
+ fd = open(*try, O_RDWR);
+ }
+ if (fd == -1) {
+ perror_msg("%s", *try);
+ continue;
+ }
+
+ // determine length
+ if (!len) len = fdlength(fd);
+ if (len<1) {
+ error_msg("%s: needs -s", *try);
+ close(fd);
+ continue;
+ }
+
+ // Loop through, writing to this file
+ for (;;) {
+ // Advance to next -n or -z?
+
+ if (pos >= len) {
+ pos = -1;
+ if (++iter == TT.iterations && (toys.optargs && FLAG_z)) {
+ memset(toybuf, 0, sizeof(toybuf));
+ continue;
+ }
+ if (iter >= TT.iterations) break;
+ }
+
+ if (pos < TT.offset) {
+ if (TT.offset != lseek(fd, TT.offset, SEEK_SET)) {
+ perror_msg("%s", *try);
+ break;
+ }
+ pos = TT.offset;
+ }
+
+ // Determine length, read random data if not zeroing, write.
+
+ throw = sizeof(toybuf);
+ if (toys.optflags & FLAG_x)
+ if (len-pos < throw) throw = len-pos;
+
+ if (iter != TT.iterations) xread(TT.ufd, toybuf, throw);
+ if (throw != writeall(fd, toybuf, throw)) perror_msg("%s");
+ pos += throw;
+ }
+ }
+}