• 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 o,n,s;)32 GLOBALS(
33   long o, n, s;
34 )
35 
36 void shred_main(void)
37 {
38   char **try;
39 
40   if (!(toys.optflags & 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 && (toys.optflags & FLAG_f)) {
51 #ifdef TOYBOX_OH_ADAPT
52       chmod(*try, 0660);
53 #else
54       chmod(*try, 0600);
55 #endif
56       fd = open(*try, O_RDWR);
57     }
58     if (fd == -1) {
59       perror_msg_raw(*try);
60       continue;
61     }
62 
63     // determine length
64     if (!len) len = fdlength(fd);
65     if (len<1) {
66       error_msg("%s: needs -s", *try);
67       close(fd);
68       continue;
69     }
70 
71     // Loop through, writing to this file
72     for (;;) {
73       // Advance to next -n or -z?
74 
75       if (pos >= len) {
76         pos = -1;
77         if (++iter == TT.n && FLAG(z)) {
78           memset(toybuf, 0, sizeof(toybuf));
79           continue;
80         }
81         if (iter >= TT.n) break;
82       }
83 
84       if (pos < TT.o) {
85         if (TT.o != lseek(fd, TT.o, SEEK_SET)) {
86           perror_msg_raw(*try);
87           break;
88         }
89         pos = TT.o;
90       }
91 
92       // Determine length, read random data if not zeroing, write.
93 
94       throw = sizeof(toybuf);
95       if (FLAG(x) && len-pos < throw) throw = len-pos;
96 
97       if (iter != TT.n) xgetrandom(toybuf, throw, 0);
98       if (throw != writeall(fd, toybuf, throw)) perror_msg_raw(*try);
99       pos += throw;
100     }
101     if (toys.optflags & FLAG_u)
102       if (unlink(*try)) perror_msg("unlink '%s'", *try);
103   }
104 }
105