10f66f451Sopenharmony_ci/* shred.c - Overwrite a file to securely delete
20f66f451Sopenharmony_ci *
30f66f451Sopenharmony_ci * Copyright 2014 Rob Landley <rob@landley.net>
40f66f451Sopenharmony_ci *
50f66f451Sopenharmony_ci * No standard
60f66f451Sopenharmony_ci
70f66f451Sopenharmony_ciUSE_SHRED(NEWTOY(shred, "<1zxus#<1n#<1o#<0f", TOYFLAG_USR|TOYFLAG_BIN))
80f66f451Sopenharmony_ci
90f66f451Sopenharmony_ciconfig SHRED
100f66f451Sopenharmony_ci  bool "shred"
110f66f451Sopenharmony_ci  default y
120f66f451Sopenharmony_ci  help
130f66f451Sopenharmony_ci    usage: shred [-fuxz] [-n COUNT] [-o OFFSET] [-s SIZE] FILE...
140f66f451Sopenharmony_ci
150f66f451Sopenharmony_ci    Securely delete a file by overwriting its contents with random data.
160f66f451Sopenharmony_ci
170f66f451Sopenharmony_ci    -f		Force (chmod if necessary)
180f66f451Sopenharmony_ci    -n COUNT	Random overwrite iterations (default 1)
190f66f451Sopenharmony_ci    -o OFFSET	Start at OFFSET
200f66f451Sopenharmony_ci    -s SIZE		Use SIZE instead of detecting file size
210f66f451Sopenharmony_ci    -u		Unlink (actually delete file when done)
220f66f451Sopenharmony_ci    -x		Use exact size (default without -s rounds up to next 4k)
230f66f451Sopenharmony_ci    -z		Zero at end
240f66f451Sopenharmony_ci
250f66f451Sopenharmony_ci    Note: data journaling filesystems render this command useless, you must
260f66f451Sopenharmony_ci    overwrite all free space (fill up disk) to erase old data on those.
270f66f451Sopenharmony_ci*/
280f66f451Sopenharmony_ci
290f66f451Sopenharmony_ci#define FOR_shred
300f66f451Sopenharmony_ci#include "toys.h"
310f66f451Sopenharmony_ci
320f66f451Sopenharmony_ciGLOBALS(
330f66f451Sopenharmony_ci  long o, n, s;
340f66f451Sopenharmony_ci)
350f66f451Sopenharmony_ci
360f66f451Sopenharmony_civoid shred_main(void)
370f66f451Sopenharmony_ci{
380f66f451Sopenharmony_ci  char **try;
390f66f451Sopenharmony_ci
400f66f451Sopenharmony_ci  if (!FLAG(n)) TT.n++;
410f66f451Sopenharmony_ci
420f66f451Sopenharmony_ci  // We don't use loopfiles() here because "-" isn't stdin, and want to
430f66f451Sopenharmony_ci  // respond to files we can't open via chmod.
440f66f451Sopenharmony_ci
450f66f451Sopenharmony_ci  for (try = toys.optargs; *try; try++) {
460f66f451Sopenharmony_ci    off_t pos = 0, len = TT.s;
470f66f451Sopenharmony_ci    int fd = open(*try, O_RDWR), iter = 0, throw;
480f66f451Sopenharmony_ci
490f66f451Sopenharmony_ci    // do -f chmod if necessary
500f66f451Sopenharmony_ci    if (fd == -1 && FLAG(f)) {
510f66f451Sopenharmony_ci      chmod(*try, 0600);
520f66f451Sopenharmony_ci      fd = open(*try, O_RDWR);
530f66f451Sopenharmony_ci    }
540f66f451Sopenharmony_ci    if (fd == -1) {
550f66f451Sopenharmony_ci      perror_msg_raw(*try);
560f66f451Sopenharmony_ci      continue;
570f66f451Sopenharmony_ci    }
580f66f451Sopenharmony_ci
590f66f451Sopenharmony_ci    // determine length
600f66f451Sopenharmony_ci    if (!len) len = fdlength(fd);
610f66f451Sopenharmony_ci    if (len<1) {
620f66f451Sopenharmony_ci      error_msg("%s: needs -s", *try);
630f66f451Sopenharmony_ci      close(fd);
640f66f451Sopenharmony_ci      continue;
650f66f451Sopenharmony_ci    }
660f66f451Sopenharmony_ci
670f66f451Sopenharmony_ci    // Loop through, writing to this file
680f66f451Sopenharmony_ci    for (;;) {
690f66f451Sopenharmony_ci      // Advance to next -n or -z?
700f66f451Sopenharmony_ci
710f66f451Sopenharmony_ci      if (pos >= len) {
720f66f451Sopenharmony_ci        pos = -1;
730f66f451Sopenharmony_ci        if (++iter == TT.n && FLAG(z)) {
740f66f451Sopenharmony_ci          memset(toybuf, 0, sizeof(toybuf));
750f66f451Sopenharmony_ci          continue;
760f66f451Sopenharmony_ci        }
770f66f451Sopenharmony_ci        if (iter >= TT.n) break;
780f66f451Sopenharmony_ci      }
790f66f451Sopenharmony_ci
800f66f451Sopenharmony_ci      if (pos < TT.o) {
810f66f451Sopenharmony_ci        if (TT.o != lseek(fd, TT.o, SEEK_SET)) {
820f66f451Sopenharmony_ci          perror_msg_raw(*try);
830f66f451Sopenharmony_ci          break;
840f66f451Sopenharmony_ci        }
850f66f451Sopenharmony_ci        pos = TT.o;
860f66f451Sopenharmony_ci      }
870f66f451Sopenharmony_ci
880f66f451Sopenharmony_ci      // Determine length, read random data if not zeroing, write.
890f66f451Sopenharmony_ci
900f66f451Sopenharmony_ci      throw = sizeof(toybuf);
910f66f451Sopenharmony_ci      if (FLAG(x) && len-pos < throw) throw = len-pos;
920f66f451Sopenharmony_ci
930f66f451Sopenharmony_ci      if (iter != TT.n) xgetrandom(toybuf, throw, 0);
940f66f451Sopenharmony_ci      if (throw != writeall(fd, toybuf, throw)) perror_msg_raw(*try);
950f66f451Sopenharmony_ci      pos += throw;
960f66f451Sopenharmony_ci    }
970f66f451Sopenharmony_ci    if (FLAG(u) && unlink(*try)) perror_msg("unlink '%s'", *try);
980f66f451Sopenharmony_ci  }
990f66f451Sopenharmony_ci}
100