1/* shred.c - Overwrite a file to securely delete 2 * 3 * Copyright 2014 Rob Landley <rob@landley.net> 4 * 5 * No standard 6 7USE_SHRED(NEWTOY(shred, "<1zxus#<1n#<1o#<0f", TOYFLAG_USR|TOYFLAG_BIN)) 8 9config 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 32GLOBALS( 33 long offset; 34 long iterations; 35 long size; 36 37 int ufd; 38) 39 40void 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