/*******************************************
    wipeIt.cpp

    A program for writing random data to disk
    in an attempt to erase any preexisting data.

    It was written for Windows, but should be
    easily addapted for any UNIX variant
    (or any with an ANSI compatible C compiler).

    Written/Addapted by Keith Oxenrider (koxenrider@sol-biotech.com)

    This program is hereby placed in the public domain, use as you will.

    This program has no warrentee, expressed or implied.

    Use at your own risk!

 ******************************************/

#include <windows.h> //for ULONG64 data type
#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <cstring>

using namespace std;

typedef unsigned long uint32; /* this value must be 32 bits in length! */
#define WIPENUM 4096          /* the block size for writing to disk, can be optimized by OS */

/*
    prng adapted from http://www.math.keio.ac.jp/~matumoto/cokus.c 
    Cokus@math.washington.edu and matumoto@math.keio.ac.jp
*/

#define N              (624)                 /* length of state vector */
#define M              (397)                 /* a period parameter */
#define K              (0x9908B0DFU)         /* a magic constant */
#define hiBit(u)       ((u) & 0x80000000U)   /* mask all but highest   bit of u */
#define loBit(u)       ((u) & 0x00000001U)   /* mask all but lowest    bit of u */
#define loBits(u)      ((u) & 0x7FFFFFFFU)   /* mask     the highest   bit of u */
#define mixBits(u, v)  (hiBit(u)|loBits(v))  /* move hi bit of u to hi bit of v */

static uint32   state[N+1];     /* state vector + 1 extra to not violate ANSI C */
static uint32   *next;          /* next random value is computed from here */
static int      left = -1;      /* can *next++ this many times before reloading */

void seedMT(uint32 seed){
    register uint32 x = (seed | 1U) & 0xFFFFFFFFU, *s = state;
    register int    j;

    for(left=0, *s++=x, j=N; --j;
        *s++ = (x*=69069U) & 0xFFFFFFFFU);
}

uint32 reloadMT(void){
    register uint32 *p0=state, *p2=state+2, *pM=state+M, s0, s1;
    register int    j;

    if(left < -1)
        seedMT(4357U);

    left=N-1, next=state+1;

    for(s0=state[0], s1=state[1], j=N-M+1; --j; s0=s1, s1=*p2++)
        *p0++ = *pM++ ^ (mixBits(s0, s1) >> 1) ^ (loBit(s1) ? K : 0U);

    for(pM=state, j=M; --j; s0=s1, s1=*p2++)
        *p0++ = *pM++ ^ (mixBits(s0, s1) >> 1) ^ (loBit(s1) ? K : 0U);

    s1=state[0], *p0 = *pM ^ (mixBits(s0, s1) >> 1) ^ (loBit(s1) ? K : 0U);
    s1 ^= (s1 >> 11);
    s1 ^= (s1 <<  7) & 0x9D2C5680U;
    s1 ^= (s1 << 15) & 0xEFC60000U;
    return(s1 ^ (s1 >> 18));
}


uint32 randomMT(void){
    uint32 y;

    if(--left < 0)
        return(reloadMT());

    y  = *next++;
    y ^= (y >> 11);
    y ^= (y <<  7) & 0x9D2C5680U;
    y ^= (y << 15) & 0xEFC60000U;
    return(y ^ (y >> 18));
}

void Usage(char * argv[]){
    fprintf(stderr, "Usage: %s <drive letter (no colon!)>\n", argv[0]);
    fprintf(stderr, "\n");
    fprintf(stderr, "This program writes randomly generated data to the root\n");
    fprintf(stderr, "directory of the drive given (this implementation is intended\n");
    fprintf(stderr, "for Windows) until it is full (file name is 'wipe.dat', be\n");
    fprintf(stderr, "sure that name is not in use!), then deletes the file.\n");
    fprintf(stderr, "The purposes of this exercise is to overwrite any deleted data.\n");
    fprintf(stderr, "\n");
    fprintf(stderr, "The prng is adapted from http://www.math.keio.ac.jp/~matumoto/cokus.c\n");
    fprintf(stderr, "\n");
    fprintf(stderr, "Written 2/11/2003 by Keith Oxenrider (koxenrider@sol-biotech.com)\n");
    fprintf(stderr, "Minor adaptations to C++ 2/20/2008 by Keith Oxenrider\n");
    fprintf(stderr, "\n");
    fprintf(stderr, "Press enter to quit.\n");
    getchar();
    exit(1);
}

#include <iostream> //somehow there is a 'left' variable in the namespace of iostream

int main(int argc, char * argv[]){
    FILE *fwipe;
    uint32 dat[WIPENUM];
    char fileName[] = "0:\\wipe.dat";
    size_t retval;
    ULONG64 cnt = 0;
    int i;
    time_t timeTot, elapsedTime;

    if (argc != 2)
        Usage(argv);
    if (strlen(argv[1]) != 1)
        Usage(argv);
    if (!isalpha(argv[1][0]))
        Usage(argv);

    fileName[0] = argv[1][0];

    seedMT((uint32)time(NULL));

    if ((fwipe = fopen(fileName, "r")) != NULL){
        fprintf(stderr, "\n\n\t%s already exists!\n\n\n", fileName);
        fclose(fwipe);
        Usage(argv);
    }

    if ((fwipe = fopen(fileName, "wb")) == NULL){
        fprintf(stderr, "\n\n\tCannot open %s!\n\n\n", fileName);
        Usage(argv);
    }

    cerr << "sizeof(dat): " << sizeof(dat) << ", sizeof(uint32): " << sizeof(uint32) << ", WIPENUM: " << WIPENUM << endl;

    time(&timeTot);

    while ((retval = fwrite(dat, sizeof(dat), 1, fwipe)) == 1){
        for (i=0;i<WIPENUM;i++){
            dat[i] = randomMT();
        }

        cnt += sizeof(dat);
        if (cnt % (sizeof(dat) * 20000) == 0){
            elapsedTime = time(NULL) - timeTot;
            cerr << "Have written " << cnt << " bytes in " << (elapsedTime / 60) << ":" << (elapsedTime % 60) << " (min:sec)\n";
        }
    }
    fclose(fwipe);
    remove(fileName);

    elapsedTime = time(NULL) - timeTot;
    cerr << "Fini.  Wrote " << cnt << " bytes in " << (elapsedTime / 60) << ":" << (elapsedTime % 60) << " min:sec\n";
    cerr << "Press enter to quit.\n";
    getchar();

    return 0;
}


