1 /* shred.c - Overwrite a file to securely delete 2 * 3 * Copyright 2014 Rob Landley <rob (at) 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 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 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 && (toys.optargs && 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 (toys.optflags & FLAG_x) 92 if (len-pos < throw) throw = len-pos; 93 94 if (iter != TT.n) xgetrandom(toybuf, throw, 0); 95 if (throw != writeall(fd, toybuf, throw)) perror_msg_raw(*try); 96 pos += throw; 97 } 98 if (toys.optflags & FLAG_u) 99 if (unlink(*try)) perror_msg("unlink '%s'", *try); 100 } 101 } 102