toybox/toys/other/shred.c
<<
>>
Prefs
   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 [-fuxz] [-n COUNT] [-o OFFSET] [-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 o, n, s;
  34)
  35
  36void shred_main(void)
  37{
  38  char **try;
  39
  40  if (!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 && 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 && 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 (FLAG(x) && len-pos < throw) throw = len-pos;
  92
  93      if (iter != TT.n) xgetrandom(toybuf, throw, 0);
  94      if (throw != writeall(fd, toybuf, throw)) perror_msg_raw(*try);
  95      pos += throw;
  96    }
  97    if (FLAG(u) && unlink(*try)) perror_msg("unlink '%s'", *try);
  98  }
  99}
 100