/* Copyright (c) 2000, Len Budney. All rights reserved. fwipe0 is provided under the BSD license. */ /* fwipe -- reads a 0-delimited list of filenames from stdin, and wipes each one in turn. Output for each file is the filename, a zero byte, a 'K' for success or a 'Z' for termporary failure or a 'D' for permanent failure, and a newline-terminated human readable status message. Note for verification purposes; stdin0 means stdin, excluding any final non-0-terminated bytes. */ #include #include #include #include #include "buffer.h" #include "error.h" #include "getln.h" #include "seek.h" #include "stralloc.h" #include "strerr.h" #include "subgetopt.h" #define FATAL "fwipe: fatal: " /* Return the integer value of str, or 0. */ int toint(char *str) { int retval = 0; /* [ str = ASCII representation of an int => retval = val(str) | else => retval = 0 ] */ while (*str) { /* [ *str = something other than int => retval = 0 ] */ if (*str < '0' || *str > '9') { retval = -1; break; } /* [ str = ASCII representation of an int => string(retval) + str := original value of str ] */ retval = retval * 10 + (*str - '0'); str++; } return retval; } /* Print a temporary failure message based on errno. */ void reject_tempsys(stralloc *f) { buffer_put(buffer_1,f->s,f->len); /* Includes terminating 0 */ buffer_puts(buffer_1,"Z"); buffer_puts(buffer_1,error_str(errno)); buffer_putsflush(buffer_1,"\n"); } /* Print a temporary failure message, based on a 0-terminated string. */ void reject_temps(stralloc *f, char *m) { buffer_put(buffer_1,f->s,f->len); /* Includes terminating 0 */ buffer_puts(buffer_1,"Z"); buffer_puts(buffer_1,m); buffer_putsflush(buffer_1,"\n"); } /* Print a success message */ void accept(stralloc *f) { buffer_put(buffer_1,f->s,f->len); /* Includes terminating 0 */ buffer_puts(buffer_1,"K"); buffer_putsflush(buffer_1,"\n"); } /* Die with a usage message. */ void die_usage(void) {strerr_die1x(100, "usage: fwipe0 [-n] [-t timeout] [-s slowness (1 - 32)]");} /* [ 0-terminated regular files on stdin wiped and deleted ] */ #define BUFSIZ 512 int main(int argc, char *argv[]) { /* [ fName, match, st := empty string, 0, empty file info ] */ stralloc fName = {0}; int match = 0; struct stat st; int fd; off_t fLen; int i,j,k; unsigned char buf0[BUFSIZ]; unsigned char buf1[BUFSIZ]; unsigned char *buf; unsigned bufsiz = sizeof(buf0); char obuf[1024]; buffer ssout; int times = 5; int del_flag = 1; int opt; unsigned long nice = 0UL; unsigned long blocks = 0UL; unsigned long moblocks = 0UL; unsigned long wait_time = 1UL; /* Read the command-line options */ while ((opt = sgopt(argc,argv,"nt:s:")) != sgoptdone) { switch(opt) { case 'n': del_flag = 0; break; case 't': times = toint(sgoptarg); if(times<0) die_usage(); break; case 's': nice = toint(sgoptarg); if(nice<1||nice>32) die_usage(); nice = 1UL<<(nice); break; case '?': die_usage(); } } /* [ buf0, buf1 := buffers of all 0 and 1 bits, respectively ] */ memset(buf0,0,bufsiz); memset(buf1,(unsigned char)0777,bufsiz); /* [ 0-terminated regular files on stdin wiped and deleted ] */ while(1) { /* [ (fName || stdin0) := stdin0 ] */ if (getln(buffer_0, &fName, &match, '\0') == -1) strerr_die2sys(111,FATAL,"unable to read stdin: "); if (!match) break; /* [ fd := descriptor for regular file fName opened for writing ] */ fd = open_write(fName.s); if (fd < 0) { reject_tempsys(&fName); continue; } if (fstat(fd,&st) < 0) { reject_tempsys(&fName); goto NEXT; } if (!S_ISREG(st.st_mode)) { reject_temps(&fName,"not a regular file"); goto NEXT; } /* [ fLen := size of file in bytes, rounded to next mult. of bufsiz ] */ fLen = st.st_size - (st.st_size%bufsiz) + bufsiz; /* [ file(fName) := overwritten 5 times w/0's and 1's ] */ for (i=0;i0; k--) { if (write(fd,buf,bufsiz)<0) { reject_tempsys(&fName); goto NEXT; } if (nice) { blocks = (blocks + 1) % nice; if(blocks == 0) { moblocks++; if(wait_time*wait_time <= moblocks) wait_time++; sleep (wait_time*wait_time); } } } if (fsync(fd)<0) { reject_tempsys(&fName); goto NEXT; } if (seek_begin(fd)<0) { reject_tempsys(&fName); goto NEXT; } } } /* [ file(fName) deleted if same size as we started with ] */ if (fstat(fd,&st) < 0) { reject_tempsys(&fName); goto NEXT; } if (st.st_size != fLen) { reject_temps(&fName,"file changed size while wiping"); goto NEXT; } close (fd); if (del_flag && unlink (fName.s)<0) {reject_tempsys(&fName); continue; } accept(&fName); continue; NEXT: close(fd); continue; } _exit(0); }