• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 = xopenro("/dev/urandom");
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