shred.c 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. /* shred.c - Overwrite a file to securely delete
  2. *
  3. * Copyright 2014 Rob Landley <rob@landley.net>
  4. *
  5. * No standard
  6. USE_SHRED(NEWTOY(shred, "<1zxus#<1n#<1o#<0f", TOYFLAG_USR|TOYFLAG_BIN))
  7. config SHRED
  8. bool "shred"
  9. default y
  10. help
  11. usage: shred [-fuxz] [-n COUNT] [-o OFFSET] [-s SIZE] FILE...
  12. Securely delete a file by overwriting its contents with random data.
  13. -f Force (chmod if necessary)
  14. -n COUNT Random overwrite iterations (default 1)
  15. -o OFFSET Start at OFFSET
  16. -s SIZE Use SIZE instead of detecting file size
  17. -u Unlink (actually delete file when done)
  18. -x Use exact size (default without -s rounds up to next 4k)
  19. -z Zero at end
  20. Note: data journaling filesystems render this command useless, you must
  21. overwrite all free space (fill up disk) to erase old data on those.
  22. */
  23. #define FOR_shred
  24. #include "toys.h"
  25. GLOBALS(
  26. long o, n, s;
  27. )
  28. void shred_main(void)
  29. {
  30. char **try;
  31. if (!FLAG(n)) TT.n++;
  32. // We don't use loopfiles() here because "-" isn't stdin, and want to
  33. // respond to files we can't open via chmod.
  34. for (try = toys.optargs; *try; try++) {
  35. off_t pos = 0, len = TT.s;
  36. int fd = open(*try, O_RDWR), iter = 0, throw;
  37. // do -f chmod if necessary
  38. if (fd == -1 && FLAG(f)) {
  39. chmod(*try, 0600);
  40. fd = open(*try, O_RDWR);
  41. }
  42. if (fd == -1) {
  43. perror_msg_raw(*try);
  44. continue;
  45. }
  46. // determine length
  47. if (!len) len = fdlength(fd);
  48. if (len<1) {
  49. error_msg("%s: needs -s", *try);
  50. close(fd);
  51. continue;
  52. }
  53. // Loop through, writing to this file
  54. for (;;) {
  55. // Advance to next -n or -z?
  56. if (pos >= len) {
  57. pos = -1;
  58. if (++iter == TT.n && FLAG(z)) {
  59. memset(toybuf, 0, sizeof(toybuf));
  60. continue;
  61. }
  62. if (iter >= TT.n) break;
  63. }
  64. if (pos < TT.o) {
  65. if (TT.o != lseek(fd, TT.o, SEEK_SET)) {
  66. perror_msg_raw(*try);
  67. break;
  68. }
  69. pos = TT.o;
  70. }
  71. // Determine length, read random data if not zeroing, write.
  72. throw = sizeof(toybuf);
  73. if (FLAG(x) && len-pos < throw) throw = len-pos;
  74. if (iter != TT.n) xgetrandom(toybuf, throw, 0);
  75. if (throw != writeall(fd, toybuf, throw)) perror_msg_raw(*try);
  76. pos += throw;
  77. }
  78. if (FLAG(u) && unlink(*try)) perror_msg("unlink '%s'", *try);
  79. }
  80. }