1 /* shred.c - Overwrite a file to securely delete
2 *
3 * Copyright 2014 Rob Landley <rob@landley.net>
4 *
5 * No standard
6
7 USE_SHRED(NEWTOY(shred, "<1zxus#<1n#<1o#<0f", TOYFLAG_USR|TOYFLAG_BIN))
8
9 config SHRED
10 bool "shred"
11 default y
12 help
13 usage: shred [-fuxz] [-n COUNT] [-o OFFSET] [-s SIZE] FILE...
14
15 Securely delete a file by overwriting its contents with random data.
16
17 -f Force (chmod if necessary)
18 -n COUNT Random overwrite iterations (default 1)
19 -o OFFSET Start at OFFSET
20 -s SIZE Use SIZE instead of detecting file size
21 -u Unlink (actually delete file when done)
22 -x Use exact size (default without -s rounds up to next 4k)
23 -z Zero at end
24
25 Note: data journaling filesystems render this command useless, you must
26 overwrite all free space (fill up disk) to erase old data on those.
27 */
28
29 #define FOR_shred
30 #include "toys.h"
31
GLOBALS(long o,n,s;)32 GLOBALS(
33 long o, n, s;
34 )
35
36 void shred_main(void)
37 {
38 char **try;
39
40 if (!FLAG(n)) TT.n++;
41
42 // We don't use loopfiles() here because "-" isn't stdin, and want to
43 // respond to files we can't open via chmod.
44
45 for (try = toys.optargs; *try; try++) {
46 off_t pos = 0, len = TT.s;
47 int fd = open(*try, O_RDWR), iter = 0, throw;
48
49 // do -f chmod if necessary
50 if (fd == -1 && FLAG(f)) {
51 chmod(*try, 0600);
52 fd = open(*try, O_RDWR);
53 }
54 if (fd == -1) {
55 perror_msg_raw(*try);
56 continue;
57 }
58
59 // determine length
60 if (!len) len = fdlength(fd);
61 if (len<1) {
62 error_msg("%s: needs -s", *try);
63 close(fd);
64 continue;
65 }
66
67 // Loop through, writing to this file
68 for (;;) {
69 // Advance to next -n or -z?
70
71 if (pos >= len) {
72 pos = -1;
73 if (++iter == TT.n && FLAG(z)) {
74 memset(toybuf, 0, sizeof(toybuf));
75 continue;
76 }
77 if (iter >= TT.n) break;
78 }
79
80 if (pos < TT.o) {
81 if (TT.o != lseek(fd, TT.o, SEEK_SET)) {
82 perror_msg_raw(*try);
83 break;
84 }
85 pos = TT.o;
86 }
87
88 // Determine length, read random data if not zeroing, write.
89
90 throw = sizeof(toybuf);
91 if (FLAG(x) && len-pos < throw) throw = len-pos;
92
93 if (iter != TT.n) xgetrandom(toybuf, throw, 0);
94 if (throw != writeall(fd, toybuf, throw)) perror_msg_raw(*try);
95 pos += throw;
96 }
97 if (FLAG(u) && unlink(*try)) perror_msg("unlink '%s'", *try);
98 }
99 }
100