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 [-fuz] [-n COUNT] [-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 offset;long iterations;long size;int ufd;)32 GLOBALS(
33 long offset;
34 long iterations;
35 long size;
36
37 int ufd;
38 )
39
40 void shred_main(void)
41 {
42 char **try;
43
44 if (!(toys.optflags & FLAG_n)) TT.iterations++;
45 TT.ufd = xopen("/dev/urandom", O_RDONLY);
46
47 // We don't use loopfiles() here because "-" isn't stdin, and want to
48 // respond to files we can't open via chmod.
49
50 for (try = toys.optargs; *try; try++) {
51 off_t pos = 0, len = TT.size;
52 int fd = open(*try, O_RDWR), iter = 0, throw;
53
54 // do -f chmod if necessary
55 if (fd == -1 && (toys.optflags & FLAG_f)) {
56 chmod(*try, 0600);
57 fd = open(*try, O_RDWR);
58 }
59 if (fd == -1) {
60 perror_msg_raw(*try);
61 continue;
62 }
63
64 // determine length
65 if (!len) len = fdlength(fd);
66 if (len<1) {
67 error_msg("%s: needs -s", *try);
68 close(fd);
69 continue;
70 }
71
72 // Loop through, writing to this file
73 for (;;) {
74 // Advance to next -n or -z?
75
76 if (pos >= len) {
77 pos = -1;
78 if (++iter == TT.iterations && (toys.optargs && FLAG_z)) {
79 memset(toybuf, 0, sizeof(toybuf));
80 continue;
81 }
82 if (iter >= TT.iterations) break;
83 }
84
85 if (pos < TT.offset) {
86 if (TT.offset != lseek(fd, TT.offset, SEEK_SET)) {
87 perror_msg_raw(*try);
88 break;
89 }
90 pos = TT.offset;
91 }
92
93 // Determine length, read random data if not zeroing, write.
94
95 throw = sizeof(toybuf);
96 if (toys.optflags & FLAG_x)
97 if (len-pos < throw) throw = len-pos;
98
99 if (iter != TT.iterations) xread(TT.ufd, toybuf, throw);
100 if (throw != writeall(fd, toybuf, throw)) perror_msg_raw(*try);
101 pos += throw;
102 }
103 if (toys.optflags & FLAG_u)
104 if (unlink(*try)) perror_msg("unlink '%s'", *try);
105 }
106 }
107