/* shred.c - Overwrite a file to securely delete * * Copyright 2014 Rob Landley <rob@landley.net> * * No standard USE_SHRED(NEWTOY(shred, "<1zxus#<1n#<1o#<0f", TOYFLAG_USR|TOYFLAG_BIN)) config SHRED bool "shred" default y help usage: shred [-fuz] [-n COUNT] [-s SIZE] FILE... Securely delete a file by overwriting its contents with random data. -f Force (chmod if necessary) -n COUNT Random overwrite iterations (default 1) -o OFFSET Start at OFFSET -s SIZE Use SIZE instead of detecting file size -u unlink (actually delete file when done) -x Use exact size (default without -s rounds up to next 4k) -z zero at end Note: data journaling filesystems render this command useless, you must overwrite all free space (fill up disk) to erase old data on those. */ #define FOR_shred #include "toys.h" GLOBALS( long offset; long iterations; long size; int ufd; ) void shred_main(void) { char **try; if (!(toys.optflags & FLAG_n)) TT.iterations++; TT.ufd = xopen("/dev/urandom", O_RDONLY); // We don't use loopfiles() here because "-" isn't stdin, and want to // respond to files we can't open via chmod. for (try = toys.optargs; *try; try++) { off_t pos = 0, len = TT.size; int fd = open(*try, O_RDWR), iter = 0, throw; // do -f chmod if necessary if (fd == -1 && (toys.optflags & FLAG_f)) { chmod(*try, 0600); fd = open(*try, O_RDWR); } if (fd == -1) { perror_msg_raw(*try); continue; } // determine length if (!len) len = fdlength(fd); if (len<1) { error_msg("%s: needs -s", *try); close(fd); continue; } // Loop through, writing to this file for (;;) { // Advance to next -n or -z? if (pos >= len) { pos = -1; if (++iter == TT.iterations && (toys.optargs && FLAG_z)) { memset(toybuf, 0, sizeof(toybuf)); continue; } if (iter >= TT.iterations) break; } if (pos < TT.offset) { if (TT.offset != lseek(fd, TT.offset, SEEK_SET)) { perror_msg_raw(*try); break; } pos = TT.offset; } // Determine length, read random data if not zeroing, write. throw = sizeof(toybuf); if (toys.optflags & FLAG_x) if (len-pos < throw) throw = len-pos; if (iter != TT.iterations) xread(TT.ufd, toybuf, throw); if (throw != writeall(fd, toybuf, throw)) perror_msg_raw(*try); pos += throw; } if (toys.optflags & FLAG_u) if (unlink(*try)) perror_msg("unlink '%s'", *try); } }