Home | History | Annotate | Download | only in other
      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 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