Index: /trunk/EraserDll/Random.cpp
===================================================================
--- /trunk/EraserDll/Random.cpp	(revision 4)
+++ /trunk/EraserDll/Random.cpp	(revision 4)
@@ -0,0 +1,2111 @@
+// Random.cpp
+//
+// Eraser. Secure data removal. For Windows.
+// Copyright © 1997-2001  Sami Tolvanen (sami@tolvanen.com).
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//
+//   Yes, all this only for overwriting. Call me crazy.
+//
+// A slightly modified version of cryptlib's cryptographically strong
+// pseudorandom number generator generator described in Peter
+// Gutmann's paper "Software generation of practically strong random
+// numbers" (1998).
+//
+// This generator also includes another output PRNG for creating large
+// amounts of random data - fast. It uses the ISAAC algorithm by Bob
+// Jenkins.
+//
+// An implementation of the Tiger/192 hash function by Ross Anderson
+// and Eli Biham is used for pool mixing and output instead of SHA-1
+// or MD5 suggested in the paper.
+//
+// The code for entropy polling has been borrowed from GNU Privacy
+// Guard 1.0.6 and cryptlib 3.0. The original source code contained
+// this copyright notice:
+
+/*
+** The random pool handling code in this module and the misc/rnd*.c
+** modules represent the cryptlib continuously seeded pseudorandom
+** number generator (CSPRNG) as described in my 1998 Usenix Security
+** Symposium paper "The generation of practically strong random
+** numbers".
+**
+** The CSPRNG code is copyright Peter Gutmann (and various others)
+** 1995-1999 all rights reserved.  Redistribution of the CSPRNG
+** modules and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+**
+** 1. Redistributions of source code must retain the above copyright
+** notice and this permission notice in its entirety.
+**
+** 2. Redistributions in binary form must reproduce the copyright
+** notice in the documentation and/or other materials provided with
+** the distribution.
+**
+** 3. A copy of any bugfixes or enhancements made must be provided
+** to the author, <pgut001@cs.auckland.ac.nz> to allow them to be
+** added to the baseline version of the code.
+**
+** ALTERNATIVELY, the code may be distributed under the terms of the
+** GNU General Public License, version 2 or any later version
+** published by the Free Software Foundation, in which case the
+** provisions of the GNU GPL are required INSTEAD OF the above
+** restrictions.
+**
+** Although not required under the terms of the GPL, it would still
+** be nice if you could make any changes available to the author to
+** allow a consistent code base to be maintained
+*/
+
+
+#include "stdafx.h"
+#include "EraserDll.h"
+#include "Common.h"
+#include "Tiger.h"
+#include "..\shared\UserInfo.h"
+#include "..\shared\key.h"
+#include "Random.h"
+#include <winioctl.h>
+#include <winperf.h>
+#include <process.h>
+
+/*
+** Variables
+*/
+
+static CRITICAL_SECTION pageLock;
+
+static E_PUINT8 poolPage = 0;
+
+static ISAAC_STATE *isaacState = 0;
+static E_PUINT32 isaacOutput = 0;
+static E_PUINT8 entropyPool = 0;
+static E_PUINT8 tempBuffer = 0;
+static E_PUINT8 outputBuffer = 0;
+
+static E_INT32 randomQuality = 0;
+static E_INT32 poolMixes = 0;
+
+static E_UINT32 isaacOutputPosition = 0;
+static LARGE_INTEGER lastCall;
+
+/*
+** Reference counter
+*/
+
+static E_INT32 refCount = 0;
+static CRITICAL_SECTION refLock;
+
+/*
+** Thread control
+*/
+
+static bool   enableSlowPoll = false;
+static HANDLE stopThreads = NULL;
+static HANDLE refreshThreadStopped = NULL;
+static HANDLE pollThreadStopped = NULL;
+
+/*
+** Declarations
+*/
+
+static UINT refreshThread(LPVOID);
+static UINT pollThread(LPVOID);
+
+
+/*
+** CryptoAPI function pointers and handles
+*/
+
+static HINSTANCE dllAdvAPI = NULL;
+static HCRYPTPROV cryptoContext = NULL;
+
+static CRYPTACQUIRECONTEXT pCryptAcquireContext = NULL;
+static CRYPTGENRANDOM pCryptGenRandom = NULL;
+static CRYPTRELEASECONTEXT pCryptReleaseContext = NULL;
+
+/*
+** CryptoAPI variables
+*/
+
+static E_UINT32 qualityCryptoAPI = qualityMicrosoft;
+
+/*
+** CryptoAPI initialization
+*/
+
+static void
+releaseCryptoAPI()
+{
+    /*
+    ** If we have acquired a context, try to release it
+    */
+
+    if (pCryptReleaseContext != NULL && cryptoContext != NULL) {
+        try {
+            pCryptReleaseContext(cryptoContext, 0);
+        } catch (...) {
+            ASSERT(0);
+        }
+    }
+    cryptoContext = NULL;
+
+    /*
+    ** Release library
+    */
+
+    if (dllAdvAPI != NULL) {
+        AfxFreeLibrary(dllAdvAPI);
+        dllAdvAPI = NULL;
+    }
+
+    /*
+    ** Clear function pointers and variables
+    */
+
+    pCryptAcquireContext = NULL;
+    pCryptGenRandom = NULL;
+    pCryptReleaseContext = NULL;
+    qualityCryptoAPI = qualityMicrosoft;
+}
+
+static void
+loadCryptoAPI()
+{
+    /*
+    ** If library isn't loaded, load it now
+    */
+
+    if (dllAdvAPI == NULL) {
+        dllAdvAPI = AfxLoadLibrary(RANDOM_MODULE_ADVAPI32);
+    }
+
+    /*
+    ** If library was found, locate functions
+    */
+
+    if (dllAdvAPI != NULL) {
+        pCryptAcquireContext = (CRYPTACQUIRECONTEXT)GetProcAddress(dllAdvAPI,
+                                                        RANDOM_FUNCTION_CRYPTACQUIRECONTEXT);
+        pCryptGenRandom = (CRYPTGENRANDOM)GetProcAddress(dllAdvAPI,
+                                                        RANDOM_FUNCTION_CRYPTGENRANDOM);
+        pCryptReleaseContext = (CRYPTRELEASECONTEXT)GetProcAddress(dllAdvAPI,
+                                                        RANDOM_FUNCTION_CRYPTRELEASECONTEXT);
+
+        if (pCryptAcquireContext != NULL && pCryptGenRandom != NULL &&
+            pCryptReleaseContext != NULL) {
+            try {
+                /*
+                ** Try to connect to Intel's hardware RNG if one is installed
+                */
+
+                if (pCryptAcquireContext(&cryptoContext, NULL, INTEL_DEF_PROV,
+                                         PROV_INTEL_SEC, 0)) {
+                    qualityCryptoAPI = qualityIntel;
+                    return;
+                }
+
+                /*
+                ** Default cryptographic service provider
+                */
+
+                qualityCryptoAPI = qualityMicrosoft;
+
+                if (pCryptAcquireContext(&cryptoContext, NULL, NULL, PROV_RSA_FULL, 0)) {
+                    return;
+                } else if (GetLastError() == NTE_BAD_KEYSET) {
+                    /*
+                    ** Default keyset may not exist, attempt to create new
+                    */
+
+                    if (pCryptAcquireContext(&cryptoContext, NULL, NULL, PROV_RSA_FULL,
+                                             CRYPT_NEWKEYSET)) {
+                        return;
+                    }
+                }
+            } catch (...) {
+                ASSERT(0);
+            }
+        }
+
+        /*
+        ** CryptoAPI not present or couldn't connect to a CSP
+        */
+
+        releaseCryptoAPI();
+    }
+}
+
+/*
+** Windows ToolHelp32 API function pointers and handles
+*/
+
+static HINSTANCE dllKernel = NULL;
+
+static CREATESNAPSHOT pCreateToolhelp32Snapshot = NULL;
+static MODULEWALK pModule32First = NULL;
+static MODULEWALK pModule32Next = NULL;
+static PROCESSWALK pProcess32First = NULL;
+static PROCESSWALK pProcess32Next = NULL;
+static THREADWALK pThread32First = NULL;
+static THREADWALK pThread32Next = NULL;
+static HEAPLISTWALK pHeap32ListFirst = NULL;
+static HEAPLISTWALK pHeap32ListNext = NULL;
+static HEAPFIRST pHeap32First = NULL;
+static HEAPNEXT pHeap32Next = NULL;
+
+/*
+** Windows ToolHelp32 API initialization
+*/
+
+static void
+releaseToolHelpAPI()
+{
+    /*
+    ** Free library
+    */
+
+    if (dllKernel != NULL) {
+        AfxFreeLibrary(dllKernel);
+        dllKernel = NULL;
+    }
+
+    /*
+    ** Clear function pointers
+    */
+
+    pCreateToolhelp32Snapshot = NULL;
+    pModule32First = NULL;
+    pModule32Next = NULL;
+    pProcess32First = NULL;
+    pProcess32Next = NULL;
+    pThread32First = NULL;
+    pThread32Next = NULL;
+    pHeap32ListFirst = NULL;
+    pHeap32ListNext = NULL;
+    pHeap32First = NULL;
+    pHeap32Next = NULL;
+}
+
+static void
+loadToolHelpAPI()
+{
+    /*
+    ** Load library, kernel should at least be present
+    */
+
+    if (dllKernel == NULL) {
+        dllKernel = AfxLoadLibrary(RANDOM_MODULE_KERNEL32);
+    }
+
+    /*
+    ** Try to locate ToolHelp32 functions
+    */
+
+    if (dllKernel != NULL) {
+        pModule32First   = (MODULEWALK)GetProcAddress(dllKernel, RANDOM_FUNCTION_MODULE32FIRST);
+        pModule32Next    = (MODULEWALK)GetProcAddress(dllKernel, RANDOM_FUNCTION_MODULE32NEXT);
+        pProcess32First  = (PROCESSWALK)GetProcAddress(dllKernel, RANDOM_FUNCTION_PROCESS32FIRST);
+        pProcess32Next   = (PROCESSWALK)GetProcAddress(dllKernel, RANDOM_FUNCTION_PROCESS32NEXT);
+        pThread32First   = (THREADWALK)GetProcAddress(dllKernel, RANDOM_FUNCTION_THREAD32FIRST);
+        pThread32Next    = (THREADWALK)GetProcAddress(dllKernel, RANDOM_FUNCTION_THREAD32NEXT);
+        pHeap32ListFirst = (HEAPLISTWALK)GetProcAddress(dllKernel, RANDOM_FUNCTION_HEAP32LISTFIRST);
+        pHeap32ListNext  = (HEAPLISTWALK)GetProcAddress(dllKernel, RANDOM_FUNCTION_HEAP32LISTNEXT);
+        pHeap32First     = (HEAPFIRST)GetProcAddress(dllKernel, RANDOM_FUNCTION_HEAPFIRST);
+        pHeap32Next      = (HEAPNEXT)GetProcAddress(dllKernel, RANDOM_FUNCTION_HEAPNEXT);
+        pCreateToolhelp32Snapshot = (CREATESNAPSHOT)GetProcAddress(dllKernel, RANDOM_FUNCTION_CREATESNAPSHOT);
+
+        if (pModule32First   != NULL && pModule32Next   != NULL &&
+            pProcess32First  != NULL && pProcess32Next  != NULL &&
+            pThread32First   != NULL && pThread32Next   != NULL &&
+            pHeap32ListFirst != NULL && pHeap32ListNext != NULL &&
+            pHeap32First     != NULL && pHeap32Next     != NULL &&
+            pCreateToolhelp32Snapshot != NULL) {
+            /*
+            ** ToolHelp32 loaded successfully
+            */
+            return;
+        }
+    }
+
+    /*
+    ** Failed to load all
+    */
+
+    releaseToolHelpAPI();
+}
+
+/*
+** Windows NT NetAPI32 function pointers and handles
+*/
+
+static HINSTANCE dllNetAPI = NULL;
+
+static NETSTATISTICSGET2 pNetStatisticsGet = NULL;
+static NETAPIBUFFERSIZE pNetApiBufferSize = NULL;
+static NETAPIBUFFERFREE pNetApiBufferFree = NULL;
+
+/*
+** Windows NT Native function pointers and handles
+*/
+
+static HINSTANCE dllNTAPI = NULL;
+static NTQUERYSYSTEMINFO pNtQuerySystemInfo = NULL;
+
+/*
+** Windows NT-specific variables
+*/
+
+static bool isNTWorkstation = false;
+
+/*
+** Windows NT-specific initialization
+*/
+
+static void
+releaseDependenciesNetAPI()
+{
+    /*
+    ** Release library
+    */
+
+    if (dllNetAPI != NULL) {
+        AfxFreeLibrary(dllNetAPI);
+        dllNetAPI = NULL;
+    }
+
+    /*
+    ** Clear function pointers
+    */
+
+    pNetStatisticsGet = NULL;
+    pNetApiBufferSize = NULL;
+    pNetApiBufferFree = NULL;
+}
+
+static void
+releaseDependenciesNativeAPI()
+{
+    /*
+    ** Release library for Native API and clean up
+    */
+
+    if (dllNTAPI != NULL) {
+        AfxFreeLibrary(dllNTAPI);
+        dllNTAPI = NULL;
+    }
+    pNtQuerySystemInfo = NULL;
+}
+
+static void
+releaseDependenciesNT()
+{
+    releaseDependenciesNetAPI();
+    releaseDependenciesNativeAPI();
+}
+
+static void
+loadDependenciesNT()
+{
+    HKEY hKey;
+
+    /*
+    ** Attempt to load NetAPI32 and locate functions
+    */
+
+    if (dllNetAPI == NULL) {
+        dllNetAPI = AfxLoadLibrary(RANDOM_MODULE_NETAPI);
+    }
+
+    if (dllNetAPI != NULL) {
+        pNetStatisticsGet = (NETSTATISTICSGET2)GetProcAddress(dllNetAPI, RANDOM_FUNCTION_NETSTATISTICSGET2);
+        pNetApiBufferSize = (NETAPIBUFFERSIZE)GetProcAddress(dllNetAPI, RANDOM_FUNCTION_NETAPIBUFFERSIZE);
+        pNetApiBufferFree = (NETAPIBUFFERFREE)GetProcAddress(dllNetAPI, RANDOM_FUNCTION_NETAPIBUFFERFREE);
+
+        if (pNetStatisticsGet == NULL || pNetApiBufferSize == NULL || pNetApiBufferFree == NULL) {
+            releaseDependenciesNetAPI();
+        }
+    }
+
+    /*
+    ** Attempt to locate Native API and load functions
+    */
+
+    if (dllNTAPI == NULL) {
+        dllNTAPI = AfxLoadLibrary(RANDOM_MODULE_NTDLL);
+    }
+
+    if (dllNTAPI != NULL) {
+        pNtQuerySystemInfo = (NTQUERYSYSTEMINFO)GetProcAddress(dllNTAPI, RANDOM_FUNCTION_NTQUERYSYSTEMINFO);
+        if (pNtQuerySystemInfo == NULL) {
+            releaseDependenciesNativeAPI();
+        }
+    }
+
+    /*
+    ** Determine whether this is NT Workstation or NT Server (for querying network statistics)
+    */
+
+    if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, RANDOM_KEY_PRODUCTOPTIONS,
+                     0, KEY_READ, &hKey) == ERROR_SUCCESS) {
+        E_UINT8 szValue[32];
+        E_UINT32 status;
+        E_UINT32 uSize = sizeof(szValue);
+
+        isNTWorkstation = true;
+        status = RegQueryValueEx(hKey, RANDOM_KEY_PRODUCTTYPE, 0,
+                                 NULL, szValue, &uSize);
+
+        if (status == ERROR_SUCCESS &&
+            stricmp((const char*)szValue, RANDOM_NTWORKSTATION_TOKEN)) {
+            isNTWorkstation = false;
+        }
+
+        RegCloseKey(hKey);
+    }
+}
+
+/*
+** Helpers
+*/
+
+static void
+clearBuffer(E_PUINT8 buffer, E_UINT32 size)
+{
+    if (size == 0) {
+        return;
+    }
+
+    /*
+    ** Fills given buffer with random, but not necessarily unpredictable data
+    */
+
+    ASSERT(hashSize >= sizeof(SYSTEMTIME));
+
+    E_UINT32 copied = 0;
+    E_UINT8 data[hashSize];
+    E_UINT8 output[hashSize];
+
+    /*
+    ** Zero fill first
+    */
+
+    ZeroMemory(buffer, size);
+
+    try {
+        /*
+        ** Hash current time N times to fill the buffer
+        */
+
+        GetSystemTime((LPSYSTEMTIME)data);
+
+        while (copied < size) {
+            tiger((E_PUINT64)data, hashSize, (E_PUINT64)output);
+
+            memcpy(&buffer[copied], output, min(hashSize, (size - copied)));
+            memcpy(data, output, hashSize);
+
+            copied += hashSize;
+        }
+    } catch (...) {
+        ASSERT(0);
+    }
+
+    ZeroMemory(data, hashSize);
+    ZeroMemory(output, hashSize);
+}
+
+/*
+** Pool management
+*/
+
+static void
+setPoolPointers(E_PUINT8 page)
+{
+    isaacState   = (ISAAC_STATE*)(page + isaacStateOffset);
+    isaacOutput  =    (E_PUINT32)(page + isaacOutputOffset);
+    entropyPool  =     (E_PUINT8)(page + poolOffset);
+    outputBuffer =     (E_PUINT8)(page + outputOffset);
+    tempBuffer   =     (E_PUINT8)(page + tempOffset);
+}
+
+static E_PUINT8
+allocatePoolPage()
+{
+    E_PUINT8 newPage = (E_PUINT8)VirtualAlloc(NULL, pageSize, MEM_COMMIT, PAGE_READWRITE);
+
+    if (newPage != NULL) {
+        /*
+        ** VirtualLock doesn't work outside NT, and even there it is
+        ** not respected when no threads are active. However, I suppose
+        ** everything helps.
+        */
+
+        VirtualLock(newPage, pageSize);
+        clearBuffer(newPage, pageSize);
+    }
+
+    return newPage;
+}
+
+static void
+freePoolPage(E_PUINT8 *page)
+{
+    if (page != NULL && *page != NULL) {
+        /*
+        ** Clear page contents and unlock before releasing memory
+        */
+
+        clearBuffer(*page, pageSize);
+        VirtualUnlock(*page, pageSize);
+
+        VirtualFree(*page, 0, MEM_RELEASE);
+        *page = NULL;
+    }
+}
+
+inline static void
+touchPool()
+{
+    static E_UINT32 index = 0;
+
+    /*
+    ** Try to keep the page in memory by touching it regularly.
+    */
+
+    /*
+    ** This won't require page locking as no significant data
+    ** is touched and the page cannot be released or moved.
+    */
+
+    try {
+        if (index >= unusedSize) {
+            index = 0;
+        }
+        poolPage[index++]--;
+    } catch (...) {
+        ASSERT(0);
+    }
+}
+
+static bool
+movePool()
+{
+    /*
+    ** Try to make it more difficult to find the pool by changing page
+    ** location in memory every now and then. May also help when trying
+    ** to keep this out of swap file.
+    */
+
+    E_PUINT8 newPage = allocatePoolPage();
+
+    if (newPage != NULL) {
+        bool result = false;
+
+        EnterCriticalSection(&pageLock);
+
+        try {
+            /*
+            ** Copy only significant portion of the page
+            */
+            memcpy(&newPage[unusedSize], &poolPage[unusedSize], pageSize - unusedSize);
+            freePoolPage(&poolPage);
+
+            poolPage = newPage;
+            newPage = NULL;
+
+            setPoolPointers(poolPage);
+
+            result = true;
+        } catch (...) {
+            if (newPage != NULL) {
+                freePoolPage(&newPage);
+            }
+            ASSERT(0);
+        }
+
+        LeaveCriticalSection(&pageLock);
+
+        return result;
+    }
+    return false;
+}
+
+/*
+** Pool mixing and adding entropy
+*/
+
+inline static void
+creditPool(const E_INT32 quality)
+{
+    if (randomQuality < requiredQuality) {
+        randomQuality += quality;
+    }
+}
+
+inline static void
+mixPool(E_PUINT8 poolPtr)
+{
+    /*
+    ** We use the temporary work area, so it cannot be mixed
+    */
+
+    ASSERT(poolPtr != tempBuffer);
+
+    /*
+    ** If no pool pointer is given, use the default entropy pool
+    */
+
+    if (poolPtr == NULL) {
+        poolPtr = entropyPool;
+
+        /*
+        ** Mixing again
+        */
+
+        if (poolMixes < requiredMixes) {
+            poolMixes++;
+        }
+    }
+
+    /*
+    ** Change something every time before generating output,
+    ** increasing the counter will do (first 64 bits of the pool)
+    */
+
+    ((E_PUINT64)poolPtr)[0]++;
+
+    /*
+    ** Treat entropyPool as a circular buffer and mix (starting from n = 0) using
+    ** hash function's compression function only:
+    **
+    ** [n] ... [n + hashSize - 1] = hash_compress([n - hashSize] ... [n + dataSize - 1])
+    */
+
+    E_UINT32 i;
+
+    /*
+    ** First hashSize bytes
+    */
+
+    memcpy(tempBuffer, &poolPtr[entropyPoolSize - hashSize], hashSize);
+    memcpy(&tempBuffer[hashSize], poolPtr, dataSize);
+
+    tiger_compress((E_PUINT64)&tempBuffer[0], (E_PUINT64)poolPtr);
+    tiger_compress((E_PUINT64)&tempBuffer[blockSize], (E_PUINT64)poolPtr);
+
+    /*
+    ** Middle blocks
+    */
+
+    for (i = 0; i < (entropyPoolSize - mixSize); i += hashSize) {
+        memcpy(tempBuffer, &poolPtr[i], mixSize);
+
+        tiger_compress((E_PUINT64)&tempBuffer[0], (E_PUINT64)&poolPtr[i + hashSize]);
+        tiger_compress((E_PUINT64)&tempBuffer[blockSize], (E_PUINT64)&poolPtr[i + hashSize]);
+    }
+
+    /*
+    ** Last < mixSize bytes
+    */
+
+    for (; i < (entropyPoolSize - hashSize); i += hashSize) {
+        memcpy(tempBuffer, &poolPtr[i], entropyPoolSize - i);
+        memcpy(&tempBuffer[entropyPoolSize - i], poolPtr, mixSize - (entropyPoolSize - i));
+
+        tiger_compress((E_PUINT64)&tempBuffer[0], (E_PUINT64)&poolPtr[i + hashSize]);
+        tiger_compress((E_PUINT64)&tempBuffer[blockSize], (E_PUINT64)&poolPtr[i + hashSize]);
+    }
+
+    /*
+    ** Clean used work area
+    */
+
+    clearBuffer(tempBuffer, mixSize);
+}
+
+inline static void
+invertPool(E_PUINT8 poolPtr)
+{
+    if (poolPtr == NULL) {
+        poolPtr = entropyPool;
+    }
+
+    /*
+    ** Invert every bit in the pool
+    */
+
+    E_PUINT32 pool = (E_PUINT32)poolPtr;
+
+    for (E_UINT32 i = 0; i < (entropyPoolSize / sizeof(E_UINT32)); i++) {
+        pool[i] ^= (E_UINT32)-1;
+    }
+}
+
+static void
+addEntropyString(E_PUINT8 buffer, E_UINT32 bytes)
+{
+    static int poolPosition = 0;
+
+    if (entropyPool == NULL) {
+        return;
+    }
+
+    /*
+    ** Adds given data to the pool, when the end is reached,
+    ** remix pools contents.
+    */
+
+    EnterCriticalSection(&pageLock);
+
+    try {
+        if (buffer == NULL) {
+            mixPool(NULL);
+        } else {
+            while (bytes--) {
+                if (poolPosition > entropyPoolSize - 1) {
+                    mixPool(NULL);
+                    poolPosition = 0;
+                }
+                entropyPool[poolPosition++] ^= *buffer++;
+            }
+        }
+    } catch (...) {
+        ASSERT(0);
+    }
+
+    LeaveCriticalSection(&pageLock);
+}
+
+#define addEntropy(pointer, size) \
+    addEntropyString((E_PUINT8)(pointer), (size))
+
+#define addEntropyValue(x) \
+    entropyValue = (E_UINT32)(x); \
+    addEntropy(&entropyValue, sizeof(E_UINT32))
+
+
+/*
+** Entropy polling
+*/
+
+#define checkStatus(x) \
+    if (WaitForSingleObject(stopThreads, 0) == WAIT_OBJECT_0) { goto x; }
+
+inline static void
+fastPoll()
+{
+    static bool fixedItemsAdded = false;
+
+    E_UINT32 entropyValue;
+    POINT point;
+    LARGE_INTEGER uCounter;
+    ULARGE_INTEGER uSpace;
+    MEMORYSTATUS msStatus;
+    FILETIME ftCreationTime;
+    FILETIME ftExitTime;
+    FILETIME ftKernelTime;
+    FILETIME ftUserTime;
+    SYSTEMTIME systemTime;
+//	PSIZE_T lpMinimumWorkingSetSize;
+//   PSIZE_T lpMaximumWorkingSetSize;
+
+	
+    try {
+        checkStatus(ExitPoll_Fast);
+
+        /*
+        ** Free disk space
+        */
+
+        eraserGetFreeDiskSpace((E_IN LPVOID)"C:\\", 3, &uSpace.QuadPart);
+        addEntropy(&uSpace, sizeof(ULARGE_INTEGER));
+
+        /*
+        ** Mouse and caret position
+        */
+
+        GetCaretPos(&point);
+        addEntropy(&point, sizeof(POINT));
+        GetCursorPos(&point);
+        addEntropy(&point, sizeof(POINT));
+
+        checkStatus(ExitPoll_Fast);
+
+        /*
+        ** Process and system information
+        */
+
+        addEntropyValue(GetActiveWindow());
+        addEntropyValue(GetCapture());
+        addEntropyValue(GetClipboardOwner());
+        addEntropyValue(GetClipboardViewer());
+        addEntropyValue(GetCurrentProcess());
+        addEntropyValue(GetCurrentProcessId());
+        addEntropyValue(GetCurrentThread());
+        addEntropyValue(GetCurrentThreadId());
+        addEntropyValue(GetDesktopWindow());
+        addEntropyValue(GetFocus());
+        addEntropyValue(GetForegroundWindow());
+        addEntropyValue(GetInputState());
+        addEntropyValue(GetMessagePos());
+        addEntropyValue(GetMessageTime());
+        addEntropyValue(GetOpenClipboardWindow());
+        addEntropyValue(GetProcessHeap());
+        addEntropyValue(GetProcessWindowStation());
+
+        checkStatus(ExitPoll_Fast);
+
+        /*
+        ** Memory status
+        */
+
+        msStatus.dwLength = sizeof(MEMORYSTATUS);
+        GlobalMemoryStatus(&msStatus);
+        addEntropy(&msStatus, sizeof(MEMORYSTATUS));
+
+        /*
+        ** These exist on NT
+        */
+
+        if (GetThreadTimes(GetCurrentThread(), &ftCreationTime, &ftExitTime,
+                &ftKernelTime, &ftUserTime)) {
+            addEntropy(&ftCreationTime, sizeof(FILETIME));
+            addEntropy(&ftExitTime,     sizeof(FILETIME));
+            addEntropy(&ftKernelTime,   sizeof(FILETIME));
+            addEntropy(&ftUserTime,     sizeof(FILETIME));
+        }
+        if (GetProcessTimes(GetCurrentProcess(), &ftCreationTime, &ftExitTime,
+                &ftKernelTime, &ftUserTime)) {
+            addEntropy(&ftCreationTime, sizeof(FILETIME));
+            addEntropy(&ftExitTime,     sizeof(FILETIME));
+            addEntropy(&ftKernelTime,   sizeof(FILETIME));
+            addEntropy(&ftUserTime,     sizeof(FILETIME));
+        }
+        //if (GetProcessWorkingSetSize(GetCurrentProcess(), &uSpace.LowPart,
+        //         &uSpace.HighPart)) {
+        //    addEntropy(&uSpace, sizeof(ULARGE_INTEGER));
+		//if (GetProcessWorkingSetSize(GetCurrentProcess(), &lpMinimumWorkingSetSize,
+        //         lpMaximumWorkingSetSize)) {
+        //    addEntropy(&lpMinimumWorkingSetSize, sizeof(PSIZE_T));
+		//	addEntropy(&lpMaximumWorkingSetSize,  sizeof(PSIZE_T));
+        //}
+
+
+        if (!fixedItemsAdded) {
+            STARTUPINFO startupInfo;
+            TIME_ZONE_INFORMATION tzi;
+            SYSTEM_INFO systemInfo;
+            OSVERSIONINFO versionInfo;
+
+            checkStatus(ExitPoll_Fast);
+
+            /*
+            ** User information
+            */
+
+            if (isWindowsNT) {
+                CString strUser, strDomain;
+
+                GetUserAndDomainName(strUser, strDomain);
+                addEntropy((LPCTSTR)strUser, strUser.GetLength());
+                addEntropy((LPCTSTR)strDomain, strDomain.GetLength());
+
+                GetCurrentUserTextualSid(strUser);
+                addEntropy((LPCTSTR)strUser, strUser.GetLength());
+            }
+            addEntropyValue(GetUserDefaultLangID());
+            addEntropyValue(GetUserDefaultLCID());
+
+            checkStatus(ExitPoll_Fast);
+
+            /*
+            ** Desktop geometry and colours
+            */
+
+            addEntropyValue(GetSystemMetrics(SM_CXSCREEN));
+            addEntropyValue(GetSystemMetrics(SM_CYSCREEN));
+            addEntropyValue(GetSystemMetrics(SM_CXHSCROLL));
+            addEntropyValue(GetSystemMetrics(SM_CYHSCROLL));
+            addEntropyValue(GetSystemMetrics(SM_CXMAXIMIZED));
+            addEntropyValue(GetSystemMetrics(SM_CYMAXIMIZED));
+            addEntropyValue(GetSysColor(COLOR_3DFACE));
+            addEntropyValue(GetSysColor(COLOR_DESKTOP));
+            addEntropyValue(GetSysColor(COLOR_INFOBK));
+            addEntropyValue(GetSysColor(COLOR_WINDOW));
+            addEntropyValue(GetDialogBaseUnits());
+
+            checkStatus(ExitPoll_Fast);
+
+            /*
+            ** System information
+            */
+
+            if (GetTimeZoneInformation(&tzi) != TIME_ZONE_ID_INVALID) {
+                addEntropy(&tzi, sizeof(TIME_ZONE_INFORMATION));
+            }
+            addEntropyValue(GetSystemDefaultLangID());
+            addEntropyValue(GetSystemDefaultLCID());
+            addEntropyValue(GetOEMCP());
+            addEntropyValue(GetACP());
+            addEntropyValue(GetKeyboardLayout(0));
+            addEntropyValue(GetKeyboardType(0));
+            addEntropyValue(GetKeyboardType(1));
+            addEntropyValue(GetKeyboardType(2));
+            addEntropyValue(GetDoubleClickTime());
+            addEntropyValue(GetCaretBlinkTime());
+            addEntropyValue(GetLogicalDrives());
+
+            checkStatus(ExitPoll_Fast);
+
+            versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+            if (GetVersionEx(&versionInfo)) {
+                addEntropy(&versionInfo, sizeof(OSVERSIONINFO));
+            }
+
+            GetSystemInfo(&systemInfo);
+            addEntropy(&systemInfo, sizeof(SYSTEM_INFO));
+
+            checkStatus(ExitPoll_Fast);
+
+
+            /*
+            ** Process startup info
+            */
+
+            startupInfo.cb = sizeof(STARTUPINFO);
+            GetStartupInfo(&startupInfo);
+            addEntropy(&startupInfo, sizeof(STARTUPINFO));
+
+            /*
+            ** Clear memory
+            */
+
+            ZeroMemory(&startupInfo, sizeof(STARTUPINFO));
+            ZeroMemory(&tzi,         sizeof(TIME_ZONE_INFORMATION));
+            ZeroMemory(&systemInfo,  sizeof(SYSTEM_INFO));
+            ZeroMemory(&versionInfo, sizeof(OSVERSIONINFO));
+
+            /*
+            ** Don't add these again
+            */
+
+            fixedItemsAdded = true;
+        }
+
+        checkStatus(ExitPoll_Fast);
+
+        /*
+        ** Counters
+        */
+
+        if (QueryPerformanceCounter(&uCounter)) {
+            addEntropy(&uCounter, sizeof(LARGE_INTEGER));
+
+            /*
+            ** Ticks since last call
+            */
+
+            lastCall.QuadPart = uCounter.QuadPart - lastCall.QuadPart;
+            addEntropy(&lastCall, sizeof(LARGE_INTEGER));
+
+            lastCall.QuadPart = uCounter.QuadPart;
+        }
+
+        addEntropyValue(GetTickCount());
+
+        /*
+        ** Time
+        */
+
+        GetSystemTime(&systemTime);
+        addEntropy(&systemTime, sizeof(SYSTEMTIME));
+
+        checkStatus(ExitPoll_Fast);
+
+        /*
+        ** Something from CryptoAPI
+        */
+
+        if (cryptoContext != NULL) {
+            E_UINT8 bytes[fastPollSize];
+
+            if (pCryptGenRandom(cryptoContext, fastPollSize, bytes)) {
+                addEntropy(bytes, fastPollSize);
+                ZeroMemory(bytes, fastPollSize);
+            }
+        }
+
+        checkStatus(ExitPoll_Fast);
+
+        /*
+        ** Quality of randomness
+        */
+
+        creditPool(qualityFastPoll);
+    } catch (...) {
+        ASSERT(0);
+    }
+
+
+    /*
+    ** Clear memory
+    */
+
+ExitPoll_Fast:
+
+    entropyValue = 0;
+
+    ZeroMemory(&point,          sizeof(POINT));
+    ZeroMemory(&uSpace,         sizeof(ULARGE_INTEGER));
+    ZeroMemory(&uCounter,       sizeof(LARGE_INTEGER));
+    ZeroMemory(&msStatus,       sizeof(MEMORYSTATUS));
+    ZeroMemory(&ftCreationTime, sizeof(FILETIME));
+    ZeroMemory(&ftExitTime,     sizeof(FILETIME));
+    ZeroMemory(&ftKernelTime,   sizeof(FILETIME));
+    ZeroMemory(&ftUserTime,     sizeof(FILETIME));
+    ZeroMemory(&systemTime,     sizeof(SYSTEMTIME));
+}
+
+
+static void
+slowPollNT()
+{
+    static bool isInitialized = false;
+    static bool isWorkstation = false;
+
+    static E_UINT32 cbPerfData = PERFORMANCE_BUFFER_SIZE;
+
+    E_PUINT8 buffer = NULL;
+    E_UINT32 uSize;
+    E_UINT32 status;
+
+    DISK_PERFORMANCE diskPerformance;
+    HANDLE hDevice;
+    CString strDevice;
+
+    E_INT32 nDrive;
+    E_INT32 iterations = 0;
+    E_INT32 performanceResults = 0;
+
+    PPERF_DATA_BLOCK pPerfData = NULL;
+
+    try {
+        pPerfData = (PPERF_DATA_BLOCK)malloc(cbPerfData);
+
+        /*
+        ** Get network statistics.
+        */
+
+        if (dllNetAPI != NULL &&
+            pNetStatisticsGet(NULL, isNTWorkstation ? SERVICE_WORKSTATION : SERVICE_SERVER,
+                              0, 0, &buffer) == 0) {
+            pNetApiBufferSize(buffer, &uSize);
+            addEntropy(buffer, uSize);
+
+            pNetApiBufferFree(buffer);
+            buffer = NULL;
+        }
+
+        /*
+        ** Get disk I/O statistics for all the hard drives
+        */
+        for (nDrive = 0; ; nDrive++) {
+            /*
+            ** If we are done, stop polling
+            */
+
+            checkStatus(ExitPoll_NT);
+
+            /*
+            ** Check whether we can access this device
+            */
+
+            strDevice.Format("\\\\.\\PhysicalDrive%d", nDrive);
+
+            hDevice = CreateFile((LPCTSTR)strDevice, 0, FILE_SHARE_READ | FILE_SHARE_WRITE,
+                                 NULL, OPEN_EXISTING, 0, NULL);
+
+            if (hDevice == INVALID_HANDLE_VALUE) {
+                break;
+            }
+
+            /*
+            ** Note: This only works if the user has turned on the disk
+            ** performance counters with 'diskperf -y'.  These counters are off
+            ** by default
+            */
+
+            if (DeviceIoControl(hDevice, IOCTL_DISK_PERFORMANCE, NULL, 0,
+                                &diskPerformance, sizeof(DISK_PERFORMANCE),
+                                &uSize, NULL)) {
+                addEntropy(&diskPerformance, uSize);
+            }
+            CloseHandle(hDevice);
+        }
+
+        /*
+        ** Query performance data. Because the Win32 version of this API (through
+        ** registry) may be buggy, try to use the NT Native API instead.
+        */
+
+        if (dllNTAPI != NULL && pPerfData != NULL) {
+            E_UINT32 uType;
+            performanceResults = 0;
+
+            /*
+            ** Scan the first 64 possible information types (we don't bother
+            ** with increasing the buffer size as we do with the Win32
+            ** version of the performance data read, we may miss a few classes
+            ** but it's no big deal).  In addition the returned size value for
+            ** some classes is wrong (eg 23 and 24 return a size of 0) so we
+            ** miss a few more things, but again it's no big deal.  This scan
+            ** typically yields around 20 pieces of data, there's nothing in
+            ** the range 65...128 so chances are there won't be anything above
+            ** there either
+            */
+
+            for (uType = 0; uType < 64; uType++) {
+                uSize = cbPerfData;
+
+                status = pNtQuerySystemInfo(uType, (E_UINT32)pPerfData,
+                                            32768, (E_UINT32)&uSize);
+
+                if (status == ERROR_SUCCESS && uSize > 0) {
+                    addEntropy(pPerfData, uSize);
+                    performanceResults++;
+
+                    /*
+                    ** Quitting already?
+                    */
+
+                    checkStatus(ExitPoll_NT);
+                }
+            }
+        }
+
+        /*
+        ** If we got enough data from Native API, we can leave now without
+        ** having to try for a Win32-level performance information query
+        */
+
+        if (performanceResults < 15) {
+            while (pPerfData != NULL && iterations++ < 10) {
+                /*
+                ** Done?
+                */
+
+                checkStatus(ExitPoll_NT);
+
+                uSize = cbPerfData;
+                status = RegQueryValueEx(HKEY_PERFORMANCE_DATA, "Global", NULL,
+                                         NULL, (E_PUINT8)pPerfData, &uSize);
+
+                if (status == ERROR_SUCCESS) {
+                    if (!memcmp(pPerfData->Signature, L"PERF", 8)) {
+                        addEntropy(pPerfData, uSize);
+                        /*
+                        ** Quality of randomness
+                        */
+
+                        creditPool(qualitySlowPoll);
+                        break;
+                    }
+                } else if (status == ERROR_MORE_DATA) {
+                    ZeroMemory(pPerfData, cbPerfData);
+
+                    cbPerfData += PERFORMANCE_BUFFER_STEP;
+                    pPerfData = (PPERF_DATA_BLOCK)realloc(pPerfData, cbPerfData);
+                }
+            }
+
+            RegCloseKey(HKEY_PERFORMANCE_DATA);
+        } else {
+            /*
+            ** Quality of randomness
+            */
+
+            creditPool(qualitySlowPoll);
+        }
+    } catch (...) {
+        ASSERT(0);
+    }
+
+    /*
+    ** Make like a tree and leave.
+    */
+
+ExitPoll_NT:
+
+    if (pPerfData != NULL) {
+        ZeroMemory(pPerfData, sizeof(PPERF_DATA_BLOCK));
+        free(pPerfData); pPerfData = NULL;
+    }
+
+    ZeroMemory(&diskPerformance, sizeof(DISK_PERFORMANCE));
+}
+
+static void
+slowPollToolHelp()
+{
+    PROCESSENTRY32 pe32;
+    THREADENTRY32 te32;
+    MODULEENTRY32 me32;
+    HEAPLIST32 hl32;
+    HEAPENTRY32 he32;
+    HANDLE hSnapshot = NULL;
+
+    try {
+        /*
+        ** Make sure ToolHelp32 API is loaded
+        */
+
+        if (pCreateToolhelp32Snapshot == NULL) {
+            return;
+        }
+
+        /*
+        ** Take a snapshot of everything we can get to which is currently
+        ** in the system
+        */
+
+        hSnapshot = pCreateToolhelp32Snapshot(TH32CS_SNAPALL, 0);
+
+        if (!hSnapshot) {
+            return;
+        }
+
+        /*
+        ** Walk through the local heap
+        */
+
+        hl32.dwSize = sizeof(HEAPLIST32);
+        he32.dwSize = sizeof(HEAPENTRY32);
+
+        if (pHeap32ListFirst(hSnapshot, &hl32)) {
+            do {
+                /*
+                ** First add the information from the basic Heaplist32
+                ** structure
+                */
+
+                addEntropy(&hl32, sizeof(HEAPLIST32));
+
+                /*
+                ** Now walk through the heap blocks getting information
+                ** on each of them
+                */
+
+                if (pHeap32First(&he32, hl32.th32ProcessID, hl32.th32HeapID)) {
+                    do {
+                        addEntropy(&he32, sizeof(HEAPENTRY32));
+                        checkStatus(ExitPoll_ToolHelp);
+                    } while (pHeap32Next(&he32));
+                }
+
+                checkStatus(ExitPoll_ToolHelp);
+
+            } while (pHeap32ListNext(hSnapshot, &hl32));
+        }
+
+        /*
+        ** Walk through all processes
+        */
+
+        pe32.dwSize = sizeof(PROCESSENTRY32);
+
+        if (pProcess32First(hSnapshot, &pe32)) {
+            do {
+                addEntropy(&pe32, sizeof(PROCESSENTRY32));
+                checkStatus(ExitPoll_ToolHelp);
+            } while(pProcess32Next(hSnapshot, &pe32));
+        }
+
+        /*
+        ** Walk through all threads
+        */
+
+        te32.dwSize = sizeof(THREADENTRY32);
+
+        if (pThread32First(hSnapshot, &te32)) {
+            do {
+                addEntropy(&te32, sizeof(THREADENTRY32));
+                checkStatus(ExitPoll_ToolHelp);
+            } while (pThread32Next(hSnapshot, &te32));
+        }
+
+        /*
+        ** Walk through all modules associated with the process
+        */
+
+        me32.dwSize = sizeof(MODULEENTRY32);
+
+        if (pModule32First(hSnapshot, &me32)) {
+            do {
+                addEntropy(&me32, sizeof(MODULEENTRY32));
+                checkStatus(ExitPoll_ToolHelp);
+            } while (pModule32Next(hSnapshot, &me32));
+        }
+
+        /*
+        ** Quality of randomness
+        */
+
+        creditPool(qualitySlowPoll);
+
+    } catch (...) {
+        ASSERT(0);
+    }
+
+ExitPoll_ToolHelp:
+
+    /*
+    ** Clean up the snapshot
+    */
+
+    CloseHandle(hSnapshot);
+
+    ZeroMemory(&pe32, sizeof(PROCESSENTRY32));
+    ZeroMemory(&te32, sizeof(THREADENTRY32));
+    ZeroMemory(&me32, sizeof(MODULEENTRY32));
+    ZeroMemory(&hl32, sizeof(HEAPLIST32));
+    ZeroMemory(&he32, sizeof(HEAPENTRY32));
+}
+
+inline static void
+slowPoll()
+{
+    try {
+        /*
+        ** Start OS specific poll
+        */
+
+        if (isWindowsNT) {
+            slowPollNT();
+        }
+
+        /*
+        ** Should we be stopping right about now?
+        */
+
+        checkStatus(ExitSlowPoll);
+
+        /*
+        ** See if ToolHelp API is available
+        */
+
+        slowPollToolHelp();
+
+        /*
+        ** Should we be stopping right about now?
+        */
+
+        checkStatus(ExitSlowPoll);
+
+        /*
+        ** CryptoAPI
+        */
+
+        if (cryptoContext != NULL) {
+            E_UINT8 bytes[slowPollSize];
+
+            if (pCryptGenRandom(cryptoContext, slowPollSize, bytes)) {
+                addEntropy(bytes, slowPollSize);
+                ZeroMemory(bytes, slowPollSize);
+
+                /*
+                ** Quality of randomness
+                */
+
+                creditPool(qualityCryptoAPI);
+            }
+        }
+
+ExitSlowPoll:
+
+        /*
+        ** Process any unmixed bytes
+        */
+
+        addEntropy(NULL, 0);
+
+    } catch (...) {
+        ASSERT(0);
+    }
+}
+
+/*
+** Thread functions
+*/
+
+static UINT
+refreshThread(LPVOID)
+{
+    E_UINT32 waitTime = 0;
+    E_UINT64 counter = 0;
+    E_UINT64 difference = 0;
+    E_UINT64 previous = 0;
+
+    ResetEvent(refreshThreadStopped);
+
+    try {
+        while (WaitForSingleObject(stopThreads, 0) != WAIT_OBJECT_0) {
+            touchPool();
+
+            if (waitTime >= poolMoveInterval) {
+                movePool();
+
+                /*
+                ** Add some more entropy to the pool
+                */
+
+                waitTime -= poolMoveInterval;
+                addEntropy(&waitTime, sizeof(E_UINT8));
+
+                waitTime = 0;
+            }
+
+            /*
+            ** Measure how much sleep time differs from the previous wait time
+            ** and add some entropy to the pool.
+            */
+
+            QueryPerformanceCounter((PLARGE_INTEGER)&difference);
+
+            /*
+            ** Sleep for a while before retouching the pool
+            */
+
+            if (WaitForSingleObject(stopThreads, poolTouchInterval) == WAIT_OBJECT_0) {
+                break;
+            }
+
+            QueryPerformanceCounter((PLARGE_INTEGER)&counter);
+            counter -= difference;
+
+            if (previous > 0) {
+                if (counter > previous) {
+                    difference = counter - previous;
+                } else {
+                    difference = previous - counter;
+                }
+
+                /*
+                ** Add one byte to the entropy pool. According to ent, this data
+                ** has ~7.24 bits of entropy for each byte, but it's not random.
+                */
+
+                addEntropy(&difference, sizeof(E_UINT8));
+            }
+
+            previous = counter;
+            waitTime += poolTouchInterval;
+
+            /*
+            ** The waitTime is naturally an approximate, we may have to wait in
+            ** addEntropy for a while and Sleep isn't obviously that accurate either.
+            */
+        }
+    } catch (...) {
+        ASSERT(0);
+    }
+
+    SetEvent(refreshThreadStopped);
+    return 0;
+}
+
+static UINT
+pollThread(LPVOID)
+{
+    ResetEvent(pollThreadStopped);
+
+    try {
+        fastPoll();
+        slowPoll();
+    } catch (...) {
+        ASSERT(0);
+    }
+
+    SetEvent(pollThreadStopped);
+    return 0;
+}
+
+
+/*
+** Exported functions
+*/
+
+void
+randomAddEntropy(E_PUINT8 buffer, E_UINT32 size)
+{
+    /*
+    ** User-provided entropy, mmm.
+    */
+
+    if (buffer != NULL && !AfxIsValidAddress(buffer, size)) {
+        return;
+    }
+    addEntropy(buffer, size);
+}
+
+bool
+randomFill(E_PUINT8 buffer, E_UINT32 size)
+{
+    if (!AfxIsValidAddress(buffer, size)) {
+        return false;
+    }
+
+    /*
+    ** Make sure we have enough entropy in the pool
+    */
+
+    if (randomQuality < requiredQuality) {
+        /*
+        ** If not, poll for more
+        */
+
+        if (enableSlowPoll) {
+            if (WaitForSingleObject(pollThreadStopped, slowPollWait) != WAIT_OBJECT_0) {
+                slowPoll();
+            }
+        }
+
+        /*
+        ** If there is still not enough entropy (i.e. slow poll failed),
+        ** run fast poll a couple of times
+        */
+
+        while (randomQuality < requiredQuality) {
+            fastPoll();
+        }
+    }
+
+    bool bResult = false;
+
+    EnterCriticalSection(&pageLock);
+
+    try {
+        /*
+        ** Do one final fast poll and mix the pool. If the pool hasn't been
+        ** mixed at least requiredMixes times, continue until it has.
+        */
+
+        do {
+            fastPoll();
+            mixPool(NULL);
+        } while (poolMixes < requiredMixes);
+
+        /*
+        ** Generate output
+        */
+
+        E_UINT32 bytesToCopy;
+        E_UINT32 bytesCopied;
+
+        for (bytesCopied = 0; bytesCopied < size; bytesCopied += outputSize) {
+
+            bytesToCopy = min(outputSize, (size - bytesCopied));
+
+            /*
+            ** Copy pool contents to a temporary buffer and invert it
+            */
+
+            memcpy(outputBuffer, entropyPool, entropyPoolSize);
+            invertPool(NULL);
+
+            /*
+            ** Mix the temporary buffer and the entropy pool
+            */
+
+            mixPool(outputBuffer);
+            mixPool(NULL);
+
+            /*
+            ** The truly paranoid would at this point perform statistical
+            ** tests to make sure the output really is random, and to catch
+            ** catastrophical failures (e.g. no/wrong/repeated output).
+            **
+            ** Luckily, this generator seems to provide satisfactory results
+            ** for me - and I am not that paranoid...
+            */
+
+            /*
+            ** Fold output to hide even a hash of previous pool contents,
+            ** and copy it to the output buffer
+            */
+
+            for (E_UINT32 i = 0; i < bytesToCopy; i++) {
+                buffer[bytesCopied + i] = (E_UINT8)(outputBuffer[i] ^ outputBuffer[outputSize + i]);
+            }
+        }
+
+        /*
+        ** Clear work area
+        */
+
+        clearBuffer(outputBuffer, entropyPoolSize);
+
+        bResult = true;
+    } catch (...) {
+        ASSERT(0);
+        try {
+            clearBuffer(outputBuffer, entropyPoolSize);
+            ZeroMemory(buffer, size);
+        } catch (...) {
+        }
+        bResult = false;
+    }
+
+    LeaveCriticalSection(&pageLock);
+
+    return bResult;
+}
+
+/*
+** ISAAC
+*/
+
+#define isaacInd(mm, x) \
+  (* (E_PUINT32) ((E_PINT8) (mm) + ((x) & (RANDOM_ISAAC_WORDS - 1) * sizeof(E_UINT32))))
+
+#define isaacStep(mix, a, b, mm, m, off, r) \
+    ( a = ((a) ^ (mix)) + (m)[off], \
+      x = *(m), \
+      *(m) = y = isaacInd(mm, x) + (a) + (b), \
+      *(r) = b = isaacInd(mm, (y) >> RANDOM_ISAAC_LOG) + x )
+
+#define isaacMix(a,b,c,d,e,f,g,h) \
+    (        a ^= b << 11, d += a, \
+     b += c, b ^= c >>  2, e += b, \
+     c += d, c ^= d <<  8, f += c, \
+     d += e, d ^= e >> 16, g += d, \
+     e += f, e ^= f << 10, h += e, \
+     f += g, f ^= g >>  4, a += f, \
+     g += h, g ^= h <<  8, b += g, \
+     h += a, h ^= a >>  9, c += h, \
+     a += b                        )
+
+inline static void
+isaacReload()
+{
+    E_UINT32 a, b;                  // Caches of a and b
+    E_UINT32 x, y;                  // Temps needed by isaacStep macro
+    E_PUINT32 m = isaacState->mm;   // Pointer into state array
+    E_PUINT32 r = isaacOutput;
+
+    a = isaacState->a;
+    b = isaacState->b + (++isaacState->c);
+
+    do {
+        isaacStep(a << 13, a, b, isaacState->mm, m,     RANDOM_ISAAC_WORDS / 2, r);
+        isaacStep(a >> 6,  a, b, isaacState->mm, m + 1, RANDOM_ISAAC_WORDS / 2, r + 1);
+        isaacStep(a << 2,  a, b, isaacState->mm, m + 2, RANDOM_ISAAC_WORDS / 2, r + 2);
+        isaacStep(a >> 16, a, b, isaacState->mm, m + 3, RANDOM_ISAAC_WORDS / 2, r + 3);
+        r += 4;
+    } while ((m += 4) < isaacState->mm + RANDOM_ISAAC_WORDS / 2);
+
+    do {
+        isaacStep(a << 13, a, b, isaacState->mm, m,     -RANDOM_ISAAC_WORDS / 2, r);
+        isaacStep(a >> 6,  a, b, isaacState->mm, m + 1, -RANDOM_ISAAC_WORDS / 2, r + 1);
+        isaacStep(a << 2,  a, b, isaacState->mm, m + 2, -RANDOM_ISAAC_WORDS / 2, r + 2);
+        isaacStep(a >> 16, a, b, isaacState->mm, m + 3, -RANDOM_ISAAC_WORDS / 2, r + 3);
+        r += 4;
+    } while ((m += 4) < isaacState->mm + RANDOM_ISAAC_WORDS);
+
+    isaacState->a = a;
+    isaacState->b = b;
+
+    a = b = x = y = 0;
+    isaacOutputPosition = 0;
+}
+
+inline static void
+isaacInit()
+{
+    E_INT32 i, j;
+
+    E_UINT32 a = 0x1367df5a;
+    E_UINT32 b = 0x95d90059;
+    E_UINT32 c = 0xc3163e4b;
+    E_UINT32 d = 0x0f421ad8;
+    E_UINT32 e = 0xd92a4a78;
+    E_UINT32 f = 0xa51a3c49;
+    E_UINT32 g = 0xc4efea1b;
+    E_UINT32 h = 0x30609119;
+
+#if 0
+    /*
+    ** The values above come from this calculation
+    */
+
+    a = b = c = d = e = f = g = h = 0x9e3779b9;  /* the golden ratio */
+    for (i = 0; i < 4; ++i) {
+        isaacMix(a, b, c, d, e, f, g, h);   /* scramble it */
+    }
+#endif
+
+    isaacState->a = isaacState->b = isaacState->c = 0;
+
+    for (j = 0; j < 2; j++) {
+        for (i = 0; i < RANDOM_ISAAC_WORDS; i += 8) {
+            a += isaacState->mm[i    ];
+            b += isaacState->mm[i + 1];
+            c += isaacState->mm[i + 2];
+            d += isaacState->mm[i + 3];
+            e += isaacState->mm[i + 4];
+            f += isaacState->mm[i + 5];
+            g += isaacState->mm[i + 6];
+            h += isaacState->mm[i + 7];
+
+            isaacMix(a, b, c, d, e, f, g, h);
+
+            isaacState->mm[i    ] = a;
+            isaacState->mm[i + 1] = b;
+            isaacState->mm[i + 2] = c;
+            isaacState->mm[i + 3] = d;
+            isaacState->mm[i + 4] = e;
+            isaacState->mm[i + 5] = f;
+            isaacState->mm[i + 6] = g;
+            isaacState->mm[i + 7] = h;
+        }
+    }
+
+    a = b = c = d = e = f = g = h = 0;
+}
+
+void
+isaacSeed()
+{
+    EnterCriticalSection(&pageLock);
+    try {
+        if (!randomFill((E_PUINT8)isaacState->mm, RANDOM_ISAAC_SEED_BYTES)) {
+            /*
+            ** Quite unlikely, but we need a seed even if randomFill fails
+            */
+            clearBuffer((E_PUINT8)isaacState->mm, RANDOM_ISAAC_BYTES);
+        }
+
+        isaacInit();
+        isaacReload();
+    } catch (...) {
+        ASSERT(0);
+    }
+    LeaveCriticalSection(&pageLock);
+}
+
+bool
+isaacFill(E_PUINT8 puBuffer, E_UINT32 uSize)
+{
+    if (!AfxIsValidAddress(puBuffer, uSize)) {
+        return false;
+    }
+
+    bool bResult = true;
+    EnterCriticalSection(&pageLock);
+
+    try {
+        E_UINT32 uAvailableData, uPosition = 0;
+        E_PUINT8 puRandom = (E_PUINT8)isaacOutput;
+        while (uPosition < uSize) {
+            /*
+            ** Refill output buffer
+            */
+
+            if (isaacOutputPosition >= RANDOM_ISAAC_BYTES) {
+                isaacReload();
+            }
+
+            /*
+            ** Amount of data to copy
+            */
+
+            uAvailableData = min((RANDOM_ISAAC_BYTES - isaacOutputPosition),
+                                 (uSize - uPosition));
+
+            /*
+            ** Copy random data to buffer
+            */
+
+            memcpy((LPVOID)&puBuffer[uPosition], (LPVOID)&puRandom[isaacOutputPosition],
+                   uAvailableData);
+
+            /*
+            ** Increase counters
+            */
+
+            isaacOutputPosition += uAvailableData;
+            uPosition += uAvailableData;
+        }
+
+        /*
+        ** Clear used random data from output buffer
+        */
+
+        clearBuffer(puRandom, isaacOutputPosition);
+    } catch (...) {
+        ASSERT(0);
+        bResult = false;
+    }
+
+    LeaveCriticalSection(&pageLock);
+    return bResult;
+}
+
+/*
+** Initialization
+*/
+
+void
+randomInit()
+{
+    EnterCriticalSection(&refLock);
+
+    try {
+        /*
+        ** Initialize if first reference
+        */
+
+        if (refCount == 0) {
+            /*
+            ** Load dynamically linked libraries and locate functions
+            */
+
+            loadCryptoAPI();
+
+            if (isWindowsNT) {
+                loadDependenciesNT();
+            }
+
+            /*
+            ** ToolHelp32 exists on Windows 9x and NT >= 5.0
+            */
+
+            loadToolHelpAPI();
+
+            /*
+            ** Allocate page and set pointers
+            */
+
+            EnterCriticalSection(&pageLock);
+
+            try {
+                poolPage = allocatePoolPage();
+                setPoolPointers(poolPage);
+            } catch (...) {
+                ASSERT(0);
+            }
+
+            LeaveCriticalSection(&pageLock);
+
+            /*
+            ** Start threads
+            */
+
+            ResetEvent(stopThreads);
+
+            SetEvent(pollThreadStopped);
+            SetEvent(refreshThreadStopped);
+
+            if (enableSlowPoll) {
+                /*
+                ** It's OK to start entropy polling thread and another one
+                ** to touch the allocated page every now and then
+                */
+                AfxBeginThread(refreshThread, 0, THREAD_PRIORITY_LOWEST);
+                AfxBeginThread(pollThread, 0);
+            }
+        }
+
+        /*
+        ** Increase reference counter
+        */
+
+        refCount++;
+    } catch (...) {
+        ASSERT(0);
+    }
+
+    LeaveCriticalSection(&refLock);
+}
+
+void
+randomEnd()
+{
+    EnterCriticalSection(&refLock);
+
+    try {
+        /*
+        ** Decrease reference counter
+        */
+
+        if (refCount > 0) {
+            refCount--;
+
+            /*
+            ** Clean up if nobody needs us anymore
+            */
+
+            if (refCount == 0) {
+                /*
+                ** Stop threads
+                */
+
+                SetEvent(stopThreads);
+                WaitForSingleObject(refreshThreadStopped, threadTermination);
+
+                /*
+                ** Free page and clear pointers
+                */
+
+                EnterCriticalSection(&pageLock);
+
+                try {
+                    freePoolPage(&poolPage);
+
+                    isaacState = 0;
+                    isaacOutput = 0;
+                    entropyPool = 0;
+                    tempBuffer = 0;
+                    outputBuffer = 0;
+                } catch (...) {
+                    ASSERT(0);
+                }
+
+                LeaveCriticalSection(&pageLock);
+
+                /*
+                ** Release loaded libraries
+                */
+
+                releaseCryptoAPI();
+
+                if (isWindowsNT) {
+                    releaseDependenciesNT();
+                }
+
+                releaseToolHelpAPI();
+            }
+        }
+    } catch (...) {
+        ASSERT(0);
+    }
+
+    LeaveCriticalSection(&refLock);
+}
+
+class __randomInit {
+public:
+    __randomInit() {
+        /*
+        ** Assumptions
+        */
+
+        /* We must be able to address the entropy pool as 32-bit words */
+        ASSERT(entropyPoolSize % sizeof(E_UINT32) == 0);
+
+        /* Tiger's compression function is called twice */
+        ASSERT(mixSize == 2 * blockSize);
+
+        /* Area that is hashed needs to be multiple of hash function's block size */
+        ASSERT((hashSize + dataSize) % blockSize == 0);
+
+        /* Entropy pool size must be multiple of hash size */
+        ASSERT(entropyPoolSize % hashSize == 0);
+
+        /* Must have enough room for work area */
+        ASSERT((pageSize - tempOffset) >= entropyPoolSize);
+
+        /*
+        ** Initialize critical sections
+        */
+
+        InitializeCriticalSection(&refLock);
+        InitializeCriticalSection(&pageLock);
+
+        /*
+        ** Initialize lastCall
+        */
+        QueryPerformanceCounter(&lastCall);
+
+        /*
+        ** Create events
+        */
+
+        stopThreads          = CreateEvent(NULL, TRUE, FALSE, NULL);
+        refreshThreadStopped = CreateEvent(NULL, TRUE, TRUE,  NULL);
+        pollThreadStopped    = CreateEvent(NULL, TRUE, TRUE,  NULL);
+
+        /*
+        ** Should we disable slow polling and memory refreshing?
+        */
+
+        enableSlowPoll = false;
+		//Currently we have disabled the background threads for adding entropy. 
+
+
+
+		/*
+
+		CKey kReg_reg;
+		CIniKey kReg_ini;
+		CKey &kReg = no_registry ? kReg_ini : kReg_reg;
+        if (kReg.Open(HKEY_CURRENT_USER, ERASER_REGISTRY_BASE)) {
+            E_UINT32 uValue;
+            kReg.GetValue(uValue, ERASER_RANDOM_SLOW_POLL, 0);
+
+            if (uValue) {
+                enableSlowPoll = true;
+            }
+
+            kReg.Close();
+        }
+		*/
+
+    }
+
+    ~__randomInit() {
+
+        /*
+        ** Just in case...
+        */
+
+        randomEnd();
+
+        /*
+        ** Clean up events
+        */
+
+        CloseHandle(stopThreads);
+        CloseHandle(refreshThreadStopped);
+        CloseHandle(pollThreadStopped);
+
+        stopThreads = NULL;
+        refreshThreadStopped = NULL;
+        pollThreadStopped = NULL;
+
+        /*
+        ** Destroy critical sections
+        */
+
+        DeleteCriticalSection(&pageLock);
+        DeleteCriticalSection(&refLock);
+    }
+};
+
+static __randomInit init;
Index: /trunk/EraserDll/CustomMethodEdit.cpp
===================================================================
--- /trunk/EraserDll/CustomMethodEdit.cpp	(revision 4)
+++ /trunk/EraserDll/CustomMethodEdit.cpp	(revision 4)
@@ -0,0 +1,608 @@
+// CustomMethodEdit.cpp
+//
+// Eraser. Secure data removal. For Windows.
+// Copyright © 1997-2001  Sami Tolvanen (sami@tolvanen.com).
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#include "stdafx.h"
+#include "eraser.h"
+#include "EraserDll.h"
+#include "commctrl.h"
+#include "CustomMethodEdit.h"
+
+#ifdef DMARS
+	#define LVCOLUMN _LV_COLUMNA
+	#define LVITEM _LV_ITEMA
+#endif
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+static const int iColumnCount = 2;
+
+static const LPSTR szColumnNames[] =
+{
+    "#",
+    "Data"
+};
+
+static int iColumnWidths[] =
+{
+    40,
+    -1
+};
+
+static void CreateList(CListCtrl& lcMethod)
+{
+    CRect rClient;
+    lcMethod.GetClientRect(&rClient);
+
+    iColumnWidths[1] = rClient.Width() -
+                       iColumnWidths[0] -
+                       2 * GetSystemMetrics(SM_CXBORDER);
+
+    LVCOLUMN lvc;
+    ZeroMemory(&lvc, sizeof(LVCOLUMN));
+
+    lvc.mask        = LVCF_FMT | LVCF_SUBITEM | LVCF_TEXT | LVCF_WIDTH;
+    lvc.fmt         = LVCFMT_LEFT;
+    lvc.pszText     = szColumnNames[0];
+    lvc.cx          = iColumnWidths[0];
+    lvc.iSubItem    = 0;
+    lcMethod.InsertColumn(0, &lvc);
+
+    lvc.mask        = LVCF_FMT | LVCF_SUBITEM | LVCF_TEXT | LVCF_WIDTH;
+    lvc.fmt         = LVCFMT_LEFT;
+    lvc.pszText     = szColumnNames[1];
+    lvc.cx          = iColumnWidths[1];
+    lvc.iSubItem    = 1;
+    lcMethod.InsertColumn(1, &lvc);
+#ifndef DMARS
+    lcMethod.SetExtendedStyle(LVS_EX_HEADERDRAGDROP | LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);
+#endif
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// CCustomMethodEdit dialog
+
+
+CCustomMethodEdit::CCustomMethodEdit(CWnd* pParent /*=NULL*/) :
+CDialog(CCustomMethodEdit::IDD, pParent),
+m_nSelectedPass((WORD)-1)
+{
+    //{{AFX_DATA_INIT(CCustomMethodEdit)
+    m_bByte2 = FALSE;
+    m_bByte3 = FALSE;
+    m_strDescription = _T("");
+    m_bShuffle = FALSE;
+    //}}AFX_DATA_INIT
+
+    m_aPasses.RemoveAll();
+}
+
+
+void CCustomMethodEdit::DoDataExchange(CDataExchange* pDX)
+{
+    CDialog::DoDataExchange(pDX);
+    //{{AFX_DATA_MAP(CCustomMethodEdit)
+    DDX_Control(pDX, IDC_EDIT_BYTE2, m_editByte2);
+    DDX_Control(pDX, IDC_EDIT_BYTE3, m_editByte3);
+    DDX_Control(pDX, IDC_EDIT_BYTE1, m_editByte1);
+    DDX_Control(pDX, IDC_LIST_PASSES, m_lcPasses);
+    DDX_Check(pDX, IDC_CHECK_BYTE2, m_bByte2);
+    DDX_Check(pDX, IDC_CHECK_BYTE3, m_bByte3);
+    DDX_Text(pDX, IDC_EDIT_DESCRIPTION, m_strDescription);
+    DDV_MaxChars(pDX, m_strDescription, (DESCRIPTION_SIZE - 1));
+    DDX_Check(pDX, IDC_CHECK_SHUFFLE, m_bShuffle);
+    //}}AFX_DATA_MAP
+}
+
+
+BEGIN_MESSAGE_MAP(CCustomMethodEdit, CDialog)
+    //{{AFX_MSG_MAP(CCustomMethodEdit)
+    ON_BN_CLICKED(IDC_BUTTON_ADD, OnButtonAdd)
+    ON_BN_CLICKED(IDC_BUTTON_COPY, OnButtonCopy)
+    ON_BN_CLICKED(IDC_BUTTON_DELETE, OnButtonDelete)
+    ON_BN_CLICKED(IDC_BUTTON_DOWN, OnButtonDown)
+    ON_BN_CLICKED(IDC_BUTTON_UP, OnButtonUp)
+    ON_BN_CLICKED(IDC_CHECK_BYTE2, OnCheckByte2)
+    ON_BN_CLICKED(IDC_CHECK_BYTE3, OnCheckByte3)
+    ON_BN_CLICKED(IDC_RADIO_PATTERN, OnRadioPattern)
+    ON_BN_CLICKED(IDC_RADIO_PSEUDORANDOM, OnRadioPseudorandom)
+    ON_NOTIFY(LVN_ITEMCHANGED, IDC_LIST_PASSES, OnItemchangedListPasses)
+    ON_EN_CHANGE(IDC_EDIT_DESCRIPTION, OnChangeEditDescription)
+    ON_EN_CHANGE(IDC_EDIT_BYTE1, OnChangeEditByte1)
+    ON_EN_CHANGE(IDC_EDIT_BYTE2, OnChangeEditByte2)
+    ON_EN_CHANGE(IDC_EDIT_BYTE3, OnChangeEditByte3)
+    //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CCustomMethodEdit message handlers
+
+BOOL CCustomMethodEdit::OnInitDialog()
+{
+    CDialog::OnInitDialog();
+
+    m_editByte1.SetByte(0);
+    m_editByte2.SetByte(0);
+    m_editByte3.SetByte(0);
+
+    CreateList(m_lcPasses);
+    UpdateList();
+
+    return TRUE;  // return TRUE unless you set the focus to a control
+                  // EXCEPTION: OCX Property Pages should return FALSE
+}
+
+void CCustomMethodEdit::OnButtonAdd()
+{
+    if (m_aPasses.GetSize() <= PASSES_MAX)
+    {
+        PASS passNew;
+        setPassOne(passNew, 0);
+
+        // array index can be used as list index as the list won't be sorted
+        int iItem = m_aPasses.Add(passNew);
+
+        UpdateList();
+        m_lcPasses.SetItemState(iItem, LVIS_SELECTED, LVIS_SELECTED);
+    }
+}
+
+void CCustomMethodEdit::OnButtonCopy()
+{
+    if (m_aPasses.GetSize() <= PASSES_MAX &&
+        m_nSelectedPass < m_aPasses.GetSize())
+    {
+        PASS passTmp = m_aPasses[m_nSelectedPass];
+        m_aPasses.InsertAt(m_nSelectedPass + 1, passTmp);
+        UpdateList();
+    }
+}
+
+void CCustomMethodEdit::OnButtonDelete()
+{
+    if (m_nSelectedPass < m_aPasses.GetSize())
+    {
+        m_aPasses.RemoveAt(m_nSelectedPass);
+        UpdateList();
+    }
+}
+
+void CCustomMethodEdit::OnButtonDown()
+{
+    if (m_nSelectedPass < (m_aPasses.GetSize() - 1))
+    {
+        PASS passTmp = m_aPasses[m_nSelectedPass + 1];
+        m_aPasses.SetAt(m_nSelectedPass + 1, m_aPasses[m_nSelectedPass]);
+        m_aPasses.SetAt(m_nSelectedPass, passTmp);
+
+        UpdateList();
+        m_lcPasses.SetItemState(m_nSelectedPass + 1, LVIS_SELECTED, LVIS_SELECTED);
+    }
+}
+
+void CCustomMethodEdit::OnButtonUp()
+{
+    if (m_nSelectedPass < m_aPasses.GetSize() &&
+        m_nSelectedPass > 0)
+    {
+        PASS passTmp = m_aPasses[m_nSelectedPass - 1];
+        m_aPasses.SetAt(m_nSelectedPass - 1, m_aPasses[m_nSelectedPass]);
+        m_aPasses.SetAt(m_nSelectedPass, passTmp);
+
+        UpdateList();
+        m_lcPasses.SetItemState(m_nSelectedPass - 1, LVIS_SELECTED, LVIS_SELECTED);
+    }
+}
+
+void CCustomMethodEdit::OnCheckByte2()
+{
+    try
+    {
+        UpdateData(TRUE);
+
+        if (!m_bByte2)
+            m_bByte3 = FALSE;
+
+        GetDlgItem(IDC_EDIT_BYTE2)->EnableWindow(m_bByte2);
+        GetDlgItem(IDC_CHECK_BYTE3)->EnableWindow(m_bByte2);
+        GetDlgItem(IDC_EDIT_BYTE3)->EnableWindow(m_bByte2 && m_bByte3);
+
+        UpdateData(FALSE);
+
+        SaveSelectedPass();
+    }
+    catch (...)
+    {
+        ASSERT(FALSE);
+    }
+}
+
+void CCustomMethodEdit::OnCheckByte3()
+{
+    try
+    {
+        SaveSelectedPass();
+        GetDlgItem(IDC_EDIT_BYTE3)->EnableWindow(m_bByte3);
+    }
+    catch (...)
+    {
+        ASSERT(FALSE);
+    }
+}
+
+void CCustomMethodEdit::OnOK()
+{
+    if (m_aPasses.GetSize() == 0)
+    {
+        if (AfxMessageBox(IDS_METHOD_NOPASSES, MB_ICONWARNING | MB_YESNO, 0) == IDYES)
+            CDialog::OnCancel();
+
+        return;
+    }
+
+    CDialog::OnOK();
+}
+
+void CCustomMethodEdit::OnRadioPattern()
+{
+    try
+    {
+        CButton *pRadioPattern = (CButton*)GetDlgItem(IDC_RADIO_PATTERN);
+        CButton *pRadioRandom  = (CButton*)GetDlgItem(IDC_RADIO_PSEUDORANDOM);
+
+        pRadioPattern->SetCheck(1);
+        pRadioRandom->SetCheck(0);
+        EnablePattern(TRUE);
+
+        SaveSelectedPass();
+    }
+    catch (...)
+    {
+        ASSERT(FALSE);
+    }
+}
+
+void CCustomMethodEdit::OnRadioPseudorandom()
+{
+    try
+    {
+        CButton *pRadioPattern = (CButton*)GetDlgItem(IDC_RADIO_PATTERN);
+        CButton *pRadioRandom  = (CButton*)GetDlgItem(IDC_RADIO_PSEUDORANDOM);
+
+        pRadioPattern->SetCheck(0);
+        pRadioRandom->SetCheck(1);
+        EnablePattern(FALSE);
+
+        SaveSelectedPass();
+    }
+    catch (...)
+    {
+        ASSERT(FALSE);
+    }
+}
+
+BOOL CCustomMethodEdit::FillCustomMethod(LPMETHOD lpcm)
+{
+    try
+    {
+        if (m_aPasses.GetSize() == 0)
+            return FALSE;
+
+        lstrcpyn(lpcm->m_szDescription, (LPCTSTR)m_strDescription, DESCRIPTION_SIZE);
+        lpcm->m_bShuffle = (BYTE)((m_aPasses.GetSize() < 2) ? 0 : m_bShuffle);
+
+        if (lpcm->m_lpPasses)
+        {
+            delete[] lpcm->m_lpPasses;
+            lpcm->m_lpPasses = 0;
+        }
+
+        lpcm->m_nPasses  = (WORD)m_aPasses.GetSize();
+        lpcm->m_lpPasses = new PASS[lpcm->m_nPasses];
+
+        for (WORD i = 0; i < lpcm->m_nPasses; i++)
+            lpcm->m_lpPasses[i] = m_aPasses[i];
+
+        return TRUE;
+    }
+    catch (CException *e)
+    {
+        e->ReportError(MB_ICONERROR);
+        e->Delete();
+    }
+
+    return FALSE;
+}
+
+BOOL CCustomMethodEdit::LoadCustomMethod(LPMETHOD lpcm)
+{
+    try
+    {
+        m_strDescription = lpcm->m_szDescription;
+        m_bShuffle       = lpcm->m_bShuffle;
+
+        for (WORD i = 0; i < lpcm->m_nPasses; i++)
+            m_aPasses.Add(lpcm->m_lpPasses[i]);
+
+        return TRUE;
+    }
+    catch (CException *e)
+    {
+        e->ReportError(MB_ICONERROR);
+        e->Delete();
+    }
+
+    return FALSE;
+}
+
+inline static CString GetByteStr(BYTE byte)
+{
+    CString str = "00000000";
+
+    for (BYTE j = 0; j < 8; j++) \
+        str.SetAt(7 - j, (byte & (1 << j)) ? '1' : '0');
+
+    return str;
+}
+
+inline static void GetPassStr(CString& str, const PASS& pass)
+{
+    if (pass.byte1 == RND_DATA)
+        str = "Pseudorandom Data";
+    else
+    {
+        str = "Pattern (" + GetByteStr((BYTE)pass.byte1);
+
+        if (pass.bytes >= 2)
+            str += " " + GetByteStr((BYTE)pass.byte2);
+        if (pass.bytes == 3)
+            str += " " + GetByteStr((BYTE)pass.byte3);
+
+        str += ")";
+    }
+}
+
+void CCustomMethodEdit::UpdateList()
+{
+    m_lcPasses.SetRedraw(FALSE);
+
+    try
+    {
+        m_lcPasses.DeleteAllItems();
+
+        CString         strTmp;
+        PASS            pass;
+        LV_ITEM         lvi;
+        ZeroMemory(&lvi, sizeof(LV_ITEM));
+
+        // built-in
+        for (WORD i = 0; i < m_aPasses.GetSize(); i++)
+        {
+            strTmp.Format("%u", (DWORD)i + 1);
+            lvi.mask        = LVIF_TEXT | LVIF_PARAM;
+            lvi.lParam      = (LPARAM)i;
+            lvi.iItem       = i;
+            lvi.iSubItem    = 0;
+            lvi.pszText     = strTmp.GetBuffer(strTmp.GetLength());
+            lvi.iItem       = m_lcPasses.InsertItem(&lvi);
+            strTmp.ReleaseBuffer();
+
+            pass = m_aPasses[i];
+            GetPassStr(strTmp, pass);
+
+            lvi.mask        = LVIF_TEXT;
+            lvi.iSubItem    = 1;
+            lvi.pszText     = strTmp.GetBuffer(strTmp.GetLength());
+            m_lcPasses.SetItem(&lvi);
+            strTmp.ReleaseBuffer();
+        }
+
+        CRect rList, rHeader;
+#ifndef DMARS
+        CSize size = m_lcPasses.ApproximateViewRect();
+#endif
+
+        m_lcPasses.GetClientRect(&rList);
+#ifndef DMARS
+        m_lcPasses.GetHeaderCtrl()->GetClientRect(&rHeader);
+#endif
+
+#ifndef DMARS
+        if (size.cy > (rList.Height() + rHeader.Height()))
+            m_lcPasses.SetColumnWidth(1, iColumnWidths[1] - GetSystemMetrics(SM_CXVSCROLL));
+        else
+#endif
+            m_lcPasses.SetColumnWidth(1, iColumnWidths[1]);
+
+        if (m_aPasses.GetSize() == 0)
+        {
+            GetDlgItem(IDC_RADIO_PATTERN)->EnableWindow(FALSE);
+            GetDlgItem(IDC_RADIO_PSEUDORANDOM)->EnableWindow(FALSE);
+            EnablePattern(FALSE);
+        }
+        else
+        {
+            if (m_nSelectedPass >= m_aPasses.GetSize())
+                m_nSelectedPass = 0;
+
+            m_lcPasses.EnsureVisible(m_nSelectedPass, FALSE);
+            m_lcPasses.SetItemState(m_nSelectedPass, LVIS_SELECTED, LVIS_SELECTED);
+        }
+    }
+    catch (...)
+    {
+        ASSERT(FALSE);
+    }
+
+    m_lcPasses.SetRedraw(TRUE);
+}
+
+void CCustomMethodEdit::OnItemchangedListPasses(NMHDR* pNMHDR, LRESULT* pResult)
+{
+    try
+    {
+        NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
+
+        if (pNMListView->uNewState != pNMListView->uOldState &&
+            pNMListView->uNewState & LVIS_SELECTED)
+        {
+            CButton *pRadioPattern = (CButton*)GetDlgItem(IDC_RADIO_PATTERN);
+            CButton *pRadioRandom  = (CButton*)GetDlgItem(IDC_RADIO_PSEUDORANDOM);
+            PASS    passTmp;
+            CString strTmp;
+
+            // get new selected item
+            LVITEM  lvi;
+            ZeroMemory(&lvi, sizeof(LVITEM));
+
+            lvi.mask  = LVIF_PARAM;
+            lvi.iItem = pNMListView->iItem;
+
+            if (m_lcPasses.GetItem(&lvi))
+            {
+                GetDlgItem(IDC_RADIO_PATTERN)->EnableWindow(TRUE);
+                GetDlgItem(IDC_RADIO_PSEUDORANDOM)->EnableWindow(TRUE);
+
+                m_nSelectedPass = (WORD)lvi.lParam;
+
+                passTmp = m_aPasses[m_nSelectedPass];
+
+                // set buttons and pass data
+                if (passTmp.byte1 == RND_DATA)
+                {
+                    pRadioRandom->SetCheck(1);
+                    pRadioPattern->SetCheck(0);
+
+                    m_bByte2 = FALSE;
+                    m_bByte3 = FALSE;
+
+                    UpdateData(FALSE);
+
+                    m_editByte1.SetByte(0);
+                    m_editByte2.SetByte(0);
+                    m_editByte3.SetByte(0);
+
+                    EnablePattern(FALSE);
+                }
+                else
+                {
+                    pRadioPattern->SetCheck(1);
+                    pRadioRandom->SetCheck(0);
+
+                    m_bByte2 = (passTmp.bytes >= 2);
+                    m_bByte3 = (passTmp.bytes == 3);
+
+                    UpdateData(FALSE);
+
+                    m_editByte1.SetByte((BYTE)passTmp.byte1);
+                    m_editByte2.SetByte(((m_bByte2) ? (BYTE)passTmp.byte2 : (BYTE)0));
+                    m_editByte3.SetByte(((m_bByte3) ? (BYTE)passTmp.byte3 : (BYTE)0));
+
+                    EnablePattern(TRUE);
+                }
+            }
+        }
+    }
+    catch (...)
+    {
+        ASSERT(FALSE);
+    }
+
+    *pResult = 0;}
+
+void CCustomMethodEdit::EnablePattern(BOOL bEnable)
+{
+    try
+    {
+        GetDlgItem(IDC_STATIC_BYTE1)->EnableWindow(bEnable);
+        GetDlgItem(IDC_CHECK_BYTE2)->EnableWindow(bEnable);
+        GetDlgItem(IDC_CHECK_BYTE3)->EnableWindow(bEnable && m_bByte2);
+
+        GetDlgItem(IDC_EDIT_BYTE1)->EnableWindow(bEnable);
+        GetDlgItem(IDC_EDIT_BYTE2)->EnableWindow(bEnable && m_bByte2);
+        GetDlgItem(IDC_EDIT_BYTE3)->EnableWindow(bEnable && m_bByte3);
+    }
+    catch (...)
+    {
+        ASSERT(FALSE);
+    }
+}
+
+void CCustomMethodEdit::OnChangeEditDescription()
+{
+    UpdateData(TRUE);
+}
+
+void CCustomMethodEdit::SaveSelectedPass()
+{
+    if (m_nSelectedPass < m_aPasses.GetSize())
+    {
+        UpdateData(TRUE);
+
+        // save possible changes to the selected pass
+        CButton *pRadioPattern = (CButton*)GetDlgItem(IDC_RADIO_PATTERN);
+        PASS    passTmp = m_aPasses[m_nSelectedPass];
+        CString strTmp;
+
+        if (pRadioPattern->GetCheck() == 1)
+        {
+            setPassOne(passTmp, 0);
+            passTmp.bytes = 1;
+
+            if (m_bByte2)
+                passTmp.bytes++;
+            if (m_bByte3)
+                passTmp.bytes++;
+
+            passTmp.byte1 = (WORD)m_editByte1.GetByte();
+
+            if (passTmp.bytes >= 2)
+                passTmp.byte2 = (WORD)m_editByte2.GetByte();
+            if (passTmp.bytes == 3)
+                passTmp.byte3 = (WORD)m_editByte3.GetByte();
+        }
+        else
+        {
+            setPassOne(passTmp, RND_DATA);
+        }
+
+        m_aPasses.SetAt(m_nSelectedPass, passTmp);
+
+        GetPassStr(strTmp, passTmp);
+        m_lcPasses.SetItemText((int)m_nSelectedPass, 1, strTmp);
+    }
+}
+
+void CCustomMethodEdit::OnChangeEditByte1()
+{
+    SaveSelectedPass();
+}
+
+void CCustomMethodEdit::OnChangeEditByte2()
+{
+    SaveSelectedPass();
+}
+
+void CCustomMethodEdit::OnChangeEditByte3()
+{
+    SaveSelectedPass();
+}
Index: /trunk/EraserDll/Eraser.cpp
===================================================================
--- /trunk/EraserDll/Eraser.cpp	(revision 4)
+++ /trunk/EraserDll/Eraser.cpp	(revision 4)
@@ -0,0 +1,2518 @@
+using namespace System::Runtime::Serialization;
+// Eraser.cpp
+//
+// Eraser. Secure data removal. For Windows.
+// Copyright © 1997-2001  Sami Tolvanen (sami@tolvanen.com).
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#include "stdafx.h"
+#include "Eraser.h"
+#include "EraserDll.h"
+#include "Common.h"
+
+#include "Options.h"
+#include "OptionsDlg.h"
+#include "ReportDialog.h"
+
+#include "RND.h"
+#include "DOD.h"
+#include "Gutmann.h"
+#include "Custom.h"
+
+#include "File.h"
+#include "NTFS.h"
+#include "FreeSpace.h"
+#include "FAT.h"
+
+#include "..\shared\FileHelper.h"
+#include "..\shared\key.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CEraserApp
+
+BEGIN_MESSAGE_MAP(CEraserApp, CWinApp)
+    //{{AFX_MSG_MAP(CEraserApp)
+        // NOTE - the ClassWizard will add and remove mapping macros here.
+        //    DO NOT EDIT what you see in these blocks of generated code!
+    //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CEraserApp construction
+
+CEraserApp::CEraserApp()
+{
+    _set_se_translator(SeTranslator);
+}
+
+BOOL CEraserApp::InitInstance()
+{
+    // determine the operating system
+    OSVERSIONINFO ov;
+    ZeroMemory(&ov, sizeof(OSVERSIONINFO));
+    ov.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+    GetVersionEx(&ov);
+
+    //isWindowsNT = (ov.dwPlatformId == VER_PLATFORM_WIN32_NT);
+	//isWindowsNT =  (ov.dwPlatformId == VER_PLATFORM_WIN32_NT  && (ov.dwMajorVersion > 5 || (ov.dwMajorVersion == 5 && ov.dwMinorVersion >= 1)));
+	isWindowsNT = (ov.dwPlatformId == VER_PLATFORM_WIN32_NT  && (ov.dwMajorVersion >= 4));
+
+    // initialize the context array
+    eraserContextArrayAccess();
+    ZeroMemory(eraserContextArray, sizeof(CEraserContext*) * (ERASER_MAX_CONTEXT + 1));
+
+    // initialize reference counter
+    eraserLibraryUnlock();
+
+    return CWinApp::InitInstance();
+}
+
+int CEraserApp::ExitInstance()
+{
+    // clean up
+    eraserLibraryUnlock();
+    eraserEnd();
+
+    return CWinApp::ExitInstance();
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+// The one and only CEraserApp object
+
+CEraserApp theApp;
+
+/////////////////////////////////////////////////////////////////////////////
+// definitions
+
+UINT eraserThread(LPVOID);
+
+/////////////////////////////////////////////////////////////////////////////
+// misc. helpers
+
+static void mySleep(UINT second) 
+{ 
+    MSG  msg; 
+    while( PeekMessage( &msg, NULL/*(HWND)this*/, 0, 0, PM_REMOVE ) ) 
+    { 
+        GetMessage( &msg, NULL, 0, 0 ); 
+        TranslateMessage(&msg); 
+        DispatchMessage(&msg); 
+    } 
+    clock_t start, finish; 
+    double  duration; 
+    start = clock(); 
+    for(;;) 
+    { 
+        finish = clock(); 
+        duration = (double)(finish - start) / CLOCKS_PER_SEC; 
+        if(duration > second) 
+        break; 
+    } 
+} 
+
+static inline bool
+overwriteFileName(LPCTSTR szFile, LPTSTR szLastFileName)
+{
+    TCHAR szNewName[MAX_PATH];
+    PTCHAR pszLastSlash;
+    E_UINT32 i, j, index, length;
+
+    try {
+        strncpy(szLastFileName, szFile, MAX_PATH);
+        pszLastSlash = strrchr(szLastFileName, '\\');
+
+        if (pszLastSlash == NULL) {
+            return false;
+        }
+
+        index = (pszLastSlash - szLastFileName) / sizeof(TCHAR);
+
+        strncpy(szNewName, szLastFileName, MAX_PATH);
+        length = (E_UINT32)strlen(szLastFileName);
+
+        for (i = 0; i < ERASER_FILENAME_PASSES; i++) {
+            // replace each non-'.' character with a random letter
+            isaacFill((E_PUINT8)(szNewName + index + 1), (length - index - 1) * sizeof(TCHAR));
+
+            for (j = index + 1; j < length; j++) {
+                if (szLastFileName[j] != '.') {
+                    szNewName[j] = ERASER_SAFEARRAY[((E_UINT16)szNewName[j]) % ERASER_SAFEARRAY_SIZE];
+                } else {
+                    szNewName[j] = '.';
+                }
+            }
+
+            if (MoveFile(szLastFileName, szNewName)) {
+                strncpy(szLastFileName, szNewName, MAX_PATH);
+            } else
+            {
+                Sleep(50); // Allow for Anti-Virus applications to stop looking at the file
+                if (MoveFile(szLastFileName, szNewName)) {
+                strncpy(szLastFileName, szNewName, MAX_PATH);
+                }
+            }
+        }
+
+        return true;
+    }
+    catch (...) {
+        ASSERT(0);
+    }
+
+    ZeroMemory(szNewName, MAX_PATH * sizeof(TCHAR));
+
+    return false;
+}
+
+static inline bool
+isFolderEmpty(LPCTSTR szFolder)
+{
+    bool            bEmpty = true;
+    HANDLE          hFind;
+    WIN32_FIND_DATA wfdData;
+    CString         strFolder(szFolder);
+
+    // make sure that the folder name ends with a backslash
+    if (strFolder[strFolder.GetLength() - 1] != '\\') {
+        strFolder += "\\";
+    }
+
+    hFind = FindFirstFile((LPCTSTR)(strFolder + "*"), &wfdData);
+
+    if (hFind != INVALID_HANDLE_VALUE) {
+        do {
+            if (bitSet(wfdData.dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY) &&
+                ISNT_SUBFOLDER(wfdData.cFileName)) {
+                continue;
+            }
+
+            bEmpty = false;
+            break;
+        }
+        while (FindNextFile(hFind, &wfdData));
+
+        VERIFY(FindClose(hFind));
+    }
+    return bEmpty;
+}
+
+// removes all files and subfolders from the given folder, use with caution
+static inline bool
+emptyFolder(LPCTSTR szFolder)
+{
+    bool            bEmpty = true;
+    HANDLE          hFind;
+    WIN32_FIND_DATA wfdData;
+    CString         strFolder(szFolder);
+    CString         strFile;
+
+    // make sure that the folder name ends with a backslash
+    if (strFolder[strFolder.GetLength() - 1] != '\\') {
+        strFolder += "\\";
+    }
+
+    hFind = FindFirstFile((LPCTSTR)(strFolder + "*"), &wfdData);
+
+    if (hFind != INVALID_HANDLE_VALUE) {
+        do {
+            strFile = strFolder + wfdData.cFileName;
+
+            if (bitSet(wfdData.dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY)) {
+                if (IS_SUBFOLDER(wfdData.cFileName)) {
+                    if (eraserError(eraserRemoveFolder((LPVOID)(LPCTSTR)strFile,
+                            (E_UINT16)strFile.GetLength(), ERASER_REMOVE_RECURSIVELY))) {
+                        bEmpty = false;
+                    }
+                }
+            } else {
+                if (eraserError(eraserRemoveFile((LPVOID)(LPCTSTR)strFile,
+                        (E_UINT16)strFile.GetLength()))) {
+                    bEmpty = false;
+                }
+            }
+        }
+        while (FindNextFile(hFind, &wfdData));
+
+        VERIFY(FindClose(hFind));
+    } else {
+        return false;
+    }
+    return bEmpty;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// context helpers
+
+static inline ERASER_RESULT
+contextToAddress(E_IN ERASER_HANDLE param1, E_OUT CEraserContext **pointer)
+{
+    // if you don't count all the error checking, this is quite fast, O(1)
+    if (!eraserContextOK(param1)) {
+        return ERASER_ERROR_PARAM1;
+    } else if (!AfxIsValidAddress(pointer, sizeof(CEraserContext*))) {
+        return ERASER_ERROR_PARAM2;
+    } else {
+        try {
+            E_UINT16 index = eraserContextIndex(param1);
+            eraserContextArrayAccess();
+            *pointer = eraserContextArray[index];
+            if (*pointer == 0) {
+                return ERASER_ERROR_PARAM1;
+            } else if (!AfxIsValidAddress(*pointer, sizeof(CEraserContext))) {
+                eraserContextArray[index] = 0;
+                *pointer = 0;
+                return ERASER_ERROR_PARAM1;
+            } else if ((*pointer)->m_uContextID != eraserContextID(param1) ||
+                       (*pointer)->m_uOwnerThreadID != ::GetCurrentThreadId()) {
+                // invalid context id or attempt to access from another thread
+                *pointer = 0;
+                return ERASER_ERROR_DENIED;
+            }
+        } catch (...) {
+            ASSERT(0);
+            return ERASER_ERROR_EXCEPTION;
+        }
+        return ERASER_OK;
+    }
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// exported functions
+
+// Library initialization
+//
+ERASER_EXPORT
+eraserInit()
+{
+    AFX_MANAGE_STATE(AfxGetStaticModuleState());
+    eraserTraceBase("eraserInit\n");
+
+    try {
+        // increase the reference counter
+        eraserLibraryInit();
+        randomInit();
+
+        return ERASER_OK;
+    } catch (...) {
+        ASSERT(0);
+        return ERASER_ERROR_EXCEPTION;
+    }
+}
+
+ERASER_EXPORT
+eraserEnd()
+{
+    AFX_MANAGE_STATE(AfxGetStaticModuleState());
+    eraserTraceBase("eraserEnd\n");
+
+    ERASER_RESULT result = ERASER_OK;
+
+    // decrease the reference counter
+    eraserLibraryUninit();
+
+    eraserContextArrayAccess();
+
+    try {
+        // if nobody else is using this instance of the library, clean up
+        if (!eraserIsLibraryInit()) {
+            for (ERASER_HANDLE i = ERASER_MIN_CONTEXT; i <= ERASER_MAX_CONTEXT; i++) {
+                if (eraserContextArray[i] != 0) {
+                    if (AfxIsValidAddress(eraserContextArray[i], sizeof(CEraserContext))) {
+                        try {
+                            // this will stop unsynchronized access to the context
+                            VERIFY(eraserOK(eraserStop(i)));
+                            eraserContextLock(eraserContextArray[i]);
+                            delete eraserContextArray[i];
+                        } catch (...) {
+                            ASSERT(0);
+                            result = ERASER_ERROR_EXCEPTION;
+                        }
+                    }
+                    eraserContextArray[i] = 0;
+                }
+            }
+        }
+
+        // decrease prng reference counter
+        randomEnd();
+    } catch (...) {
+        ASSERT(0);
+        result = ERASER_ERROR_EXCEPTION;
+    }
+
+    return result;
+}
+
+
+// Context creation and destruction
+//
+ERASER_EXPORT
+eraserCreateContext(E_OUT ERASER_HANDLE *param1)
+{
+    AFX_MANAGE_STATE(AfxGetStaticModuleState());
+    eraserTraceBase("eraserCreateContext\n");
+
+    if (!eraserIsLibraryInit()) {
+        return ERASER_ERROR_INIT;
+    } else if (!AfxIsValidAddress(param1, sizeof(ERASER_HANDLE))) {
+        return ERASER_ERROR_PARAM1;
+    } else {
+        try {
+            *param1 = ERASER_INVALID_CONTEXT;
+        } catch (...) {
+            return ERASER_ERROR_PARAM1;
+        }
+    }
+
+    eraserContextArrayAccess();
+
+    // find first available context
+    for (E_UINT16 i = ERASER_MAX_CONTEXT; i >= ERASER_MIN_CONTEXT; i--) {
+        if (eraserContextArray[i] == 0) {
+            try {
+                eraserContextArray[i] = new CEraserContext();
+            } catch (...) {
+                eraserContextArray[i] = 0;
+                return ERASER_ERROR_MEMORY;
+            }
+
+            try {
+                if (!loadLibrarySettings(&eraserContextArray[i]->m_lsSettings)) {
+                    setLibraryDefaults(&eraserContextArray[i]->m_lsSettings);
+                }
+
+                // reseed the prng
+                isaacSeed();
+
+                // context identification
+                isaacFill((E_PUINT8)&eraserContextArray[i]->m_uContextID, sizeof(E_UINT16));
+                eraserContextArray[i]->m_uOwnerThreadID = ::GetCurrentThreadId();
+
+                // context handle is a combination of eraserContextArray
+                // index and the number of times this function is called
+                eraserSetContextID(*param1, eraserContextArray[i]->m_uContextID);
+                eraserSetContextIndex(*param1, i);
+            } catch (...) {
+                ASSERT(0);
+                if (AfxIsValidAddress(eraserContextArray[i], sizeof(CEraserContext))) {
+                    delete eraserContextArray[i];
+                    eraserContextArray[i] = 0;
+                }
+                return ERASER_ERROR_EXCEPTION;
+            }
+            return ERASER_OK;
+        }
+    }
+
+    return ERASER_ERROR_CONTEXT;
+}
+
+E_UINT8 convEraseMethod(ERASER_METHOD mIn)
+{
+	switch(mIn){
+		case ERASER_METHOD_LIBRARY:
+			return GUTMANN_METHOD_ID;
+			break;
+		case ERASER_METHOD_GUTMANN:
+			return GUTMANN_METHOD_ID;
+			break;
+		case ERASER_METHOD_DOD:
+			return DOD_METHOD_ID;
+			break;
+		case ERASER_METHOD_DOD_E:
+			return DOD_E_METHOD_ID;
+			break;
+		case ERASER_METHOD_PSEUDORANDOM:
+			return RANDOM_METHOD_ID;
+			break;
+		case ERASER_METHOD_FIRST_LAST_2KB:
+			return FL2KB_METHOD_ID;
+			break;
+        case ERASER_METHOD_SCHNEIER:
+			return SCHNEIER_METHOD_ID;
+			break;
+		default:
+			return mIn;
+	}
+}
+
+ERASER_EXPORT
+eraserCreateContextEx(E_OUT ERASER_HANDLE *param1, E_IN E_UINT8 param2, E_IN E_UINT16 param3, E_IN E_UINT8 param4)
+{
+    AFX_MANAGE_STATE(AfxGetStaticModuleState());
+    eraserTraceBase("eraserCreateContextEx\n");
+    LONG lRetStatus = ERASER_OK;
+	if (param2==0) {
+        return ERASER_ERROR_PARAM2;
+    } else if (param3 > PASSES_MAX || param3 < 1) {
+        return ERASER_ERROR_PARAM3;
+    }
+
+    // this one does all our basic sanity checks
+    ERASER_RESULT result = eraserCreateContext(param1);
+    if (eraserError(result)) {
+        return result;
+    } else {
+        try {
+            CEraserContext *context = 0;
+            if (eraserOK(contextToAddress(*param1, &context))) {
+                eraserContextAccess(context);
+                if (param4) {
+                    context->m_lsSettings.m_uItems = param4;
+                }
+                switch (param2) {
+                case GUTMANN_METHOD_ID:
+                    context->m_lsSettings.m_nFileMethodID = GUTMANN_METHOD_ID;
+                    context->m_lsSettings.m_nUDSMethodID  = GUTMANN_METHOD_ID;
+                    break;
+                case DOD_METHOD_ID:
+                    context->m_lsSettings.m_nFileMethodID = DOD_METHOD_ID;
+                    context->m_lsSettings.m_nUDSMethodID  = DOD_METHOD_ID;
+                    break;
+                case DOD_E_METHOD_ID:
+                    context->m_lsSettings.m_nFileMethodID = DOD_E_METHOD_ID;
+                    context->m_lsSettings.m_nUDSMethodID  = DOD_E_METHOD_ID;
+                    break;
+                case RANDOM_METHOD_ID:
+                    context->m_lsSettings.m_nFileMethodID = RANDOM_METHOD_ID;
+                    context->m_lsSettings.m_nUDSMethodID  = RANDOM_METHOD_ID;
+                    context->m_lsSettings.m_nFileRandom   = param3;
+                    context->m_lsSettings.m_nUDSRandom    = param3;
+                    break;
+				case FL2KB_METHOD_ID:
+                    context->m_lsSettings.m_nFileMethodID = FL2KB_METHOD_ID;
+                    context->m_lsSettings.m_nUDSMethodID  = FL2KB_METHOD_ID;
+					break;
+				case SCHNEIER_METHOD_ID:
+                    context->m_lsSettings.m_nFileMethodID = SCHNEIER_METHOD_ID;
+                    context->m_lsSettings.m_nUDSMethodID  = SCHNEIER_METHOD_ID;
+					break;
+                default:
+					{
+						LibrarySettings lsTemp;
+						BOOL bExist = FALSE;
+						if (loadLibrarySettings(&lsTemp))
+						{
+							for(int i = 0; i < lsTemp.m_nCMethods; i++)
+								if (lsTemp.m_lpCMethods->m_nMethodID == param2) bExist = TRUE;
+							if (bExist) {
+								context->m_lsSettings.m_nFileMethodID = param2;
+								context->m_lsSettings.m_nUDSMethodID  = param2;
+							}
+							else { 
+								//eraserDestroyContext(*param1);
+								lRetStatus = ERASER_ERROR_PARAM2;
+								//break;
+							}
+						}
+						else{
+							//eraserDestroyContext(*param1);
+							lRetStatus = ERASER_ERROR_PARAM2;
+							//break;
+						}
+					}
+                }
+
+                return lRetStatus;
+            }
+            return ERASER_ERROR_CONTEXT;
+
+        } catch (...) {
+            ASSERT(0);
+            try {
+                eraserDestroyContext(*param1);
+            } catch (...) {
+            }
+            return ERASER_ERROR_EXCEPTION;
+        }
+    }
+}
+
+ERASER_EXPORT
+eraserDestroyContext(E_IN ERASER_HANDLE param1)
+{
+    AFX_MANAGE_STATE(AfxGetStaticModuleState());
+    eraserTraceBase("eraserDestroyContext\n");
+    if (!eraserIsLibraryInit()) {
+        return ERASER_ERROR_INIT;
+    }
+
+    CEraserContext *context = 0;
+    if (eraserError(contextToAddress(param1, &context))) {
+        return ERASER_ERROR_PARAM1;
+    } else {
+        try {
+            // make sure we are not running this one
+            VERIFY(eraserOK(eraserStop(param1)));
+            // remove from array
+            eraserContextArrayAccess();
+            eraserContextArray[eraserContextIndex(param1)] = 0;
+            eraserContextArrayRelease();
+            // free the memory
+            eraserContextLock(context);
+            delete context;
+            context = 0;
+        } catch (...) {
+            ASSERT(0);
+            return ERASER_ERROR_EXCEPTION;
+        }
+        return ERASER_OK;
+    }
+}
+
+ERASER_EXPORT
+eraserIsValidContext(E_IN ERASER_HANDLE param1)
+{
+    AFX_MANAGE_STATE(AfxGetStaticModuleState());
+    eraserTraceQuery("eraserIsValidContext\n");
+    if (!eraserIsLibraryInit()) {
+        return ERASER_ERROR_INIT;
+    }
+
+    CEraserContext *context = 0;
+    if (eraserError(contextToAddress(param1, &context))) {
+        return ERASER_ERROR_PARAM1;
+    } else {
+        return ERASER_OK;
+    }
+}
+//Error handler
+ERASER_EXPORT
+eraserSetErrorHandler(E_IN ERASER_HANDLE param1, EraserErrorHandler pfn, void* fnParam)
+{
+	CEraserContext *context = 0;
+	if (eraserError(contextToAddress(param1, &context))) 
+	{
+		return ERASER_ERROR_PARAM1;
+	} 
+	else if (eraserInternalIsRunning(context)) 
+	{
+		return ERASER_ERROR_RUNNING;
+	} 
+	else 
+	{
+		try 
+		{
+
+			eraserContextAccess(context);
+			context->m_pfnErrorHandler = pfn;
+			context->m_pErrorHandlerParam = fnParam;
+
+
+		} 
+		catch (...) 
+		{
+			ASSERT(0);
+			return ERASER_ERROR_EXCEPTION;
+		}
+		return ERASER_OK;
+	}
+
+}
+
+// Data type
+//
+ERASER_EXPORT
+eraserSetDataType(E_IN ERASER_HANDLE param1, E_IN ERASER_DATA_TYPE param2)
+{
+    AFX_MANAGE_STATE(AfxGetStaticModuleState());
+    eraserTraceBase("eraserSetDataType\n");
+    if (!eraserIsLibraryInit()) {
+        return ERASER_ERROR_INIT;
+    }
+
+    CEraserContext *context = 0;
+    if (!eraserIsValidDataType(param2)) {
+        return ERASER_ERROR_PARAM2;
+    } else if (eraserError(contextToAddress(param1, &context))) {
+        return ERASER_ERROR_PARAM1;
+    } else if (eraserInternalIsRunning(context)) {
+        return ERASER_ERROR_RUNNING;
+    } else {
+        try {
+            eraserContextAccess(context);
+            if (context->m_saData.GetSize() == 0) {
+                context->m_edtDataType = param2;
+            } else {
+                // cannot change data type after adding items to erase
+                return ERASER_ERROR_DENIED;
+            }
+        } catch (...) {
+            ASSERT(0);
+            return ERASER_ERROR_EXCEPTION;
+        }
+        return ERASER_OK;
+    }
+}
+
+ERASER_EXPORT
+eraserGetDataType(E_IN ERASER_HANDLE param1, E_OUT ERASER_DATA_TYPE *param2)
+{
+    AFX_MANAGE_STATE(AfxGetStaticModuleState());
+    eraserTraceQuery("eraserGetDataType\n");
+    if (!eraserIsLibraryInit()) {
+        return ERASER_ERROR_INIT;
+    }
+
+    CEraserContext *context = 0;
+    if (!AfxIsValidAddress(param2, sizeof(ERASER_DATA_TYPE))) {
+        return ERASER_ERROR_PARAM2;
+    } else if (eraserError(contextToAddress(param1, &context))) {
+        return ERASER_ERROR_PARAM1;
+    } else {
+        try {
+            eraserContextAccess(context);
+            *param2 = context->m_edtDataType;
+        } catch (...) {
+            ASSERT(0);
+            return ERASER_ERROR_EXCEPTION;
+        }
+        return ERASER_OK;
+    }
+}
+
+
+// Assign data
+//
+ERASER_EXPORT
+eraserAddItem(E_IN ERASER_HANDLE param1, E_IN LPVOID param2, E_IN E_UINT16 param3)
+{
+    AFX_MANAGE_STATE(AfxGetStaticModuleState());
+    eraserTraceBase("eraserAddItem\n");
+    if (!eraserIsLibraryInit()) {
+        return ERASER_ERROR_INIT;
+    }
+
+    CEraserContext *context = 0;
+    if (param3 < _MAX_DRIVE || param3 > _MAX_PATH) {
+        return ERASER_ERROR_PARAM3;
+    } else if (!AfxIsValidString((LPCTSTR)param2, param3)) {
+        return ERASER_ERROR_PARAM2;
+    } else if (eraserError(contextToAddress(param1, &context))) {
+        return ERASER_ERROR_PARAM1;
+    } else if (eraserInternalIsRunning(context)) {
+        return ERASER_ERROR_RUNNING;
+    } else {
+        try {
+            LPCTSTR szItem = (LPCTSTR)param2;
+
+            // if the item is a file, a fully qualified name is required,
+            // drive must be given as "X:\\"
+
+            if (!isalpha(szItem[0]) || szItem[1] != ':' || szItem[2] != '\\') {
+                return ERASER_ERROR_PARAM2;
+            }
+
+            eraserContextAccess(context);
+
+            if ((context->m_edtDataType == ERASER_DATA_FILES  && strlen(szItem) > _MAX_PATH) ||
+                (context->m_edtDataType == ERASER_DATA_DRIVES && strlen(szItem) > _MAX_DRIVE)) {
+                return ERASER_ERROR_PARAM2;
+            } else {
+                context->m_saData.Add(szItem);
+            }
+        } catch (...) {
+            ASSERT(0);
+            return ERASER_ERROR_EXCEPTION;
+        }
+        return ERASER_OK;
+    }
+}
+
+ERASER_EXPORT
+eraserSetFinishAction(E_IN ERASER_HANDLE param1, E_IN DWORD action)
+{
+	CEraserContext *context = 0;
+	if (eraserError(contextToAddress(param1, &context))) {
+		return ERASER_ERROR_PARAM1;
+	} else if (eraserInternalIsRunning(context)) {
+		return ERASER_ERROR_RUNNING;
+	} else {
+		try {
+			
+			eraserContextAccess(context);
+			context->m_dwFinishAction = action;
+
+			
+		} catch (...) {
+			ASSERT(0);
+			return ERASER_ERROR_EXCEPTION;
+		}
+		return ERASER_OK;
+	}
+
+}
+ERASER_EXPORT
+eraserClearItems(E_IN ERASER_HANDLE param1)
+{
+    AFX_MANAGE_STATE(AfxGetStaticModuleState());
+    eraserTraceBase("eraserClearItems\n");
+    if (!eraserIsLibraryInit()) {
+        return ERASER_ERROR_INIT;
+    }
+
+    CEraserContext *context = 0;
+    if (eraserError(contextToAddress(param1, &context))) {
+        return ERASER_ERROR_PARAM1;
+    } else if (eraserInternalIsRunning(context)) {
+        return ERASER_ERROR_RUNNING;
+    } else {
+        try {
+            eraserContextAccess(context);
+            context->m_saData.RemoveAll();
+        } catch (...) {
+            ASSERT(0);
+            return ERASER_ERROR_EXCEPTION;
+        }
+        return ERASER_OK;
+    }
+}
+
+
+// Notification
+//
+ERASER_EXPORT
+eraserSetWindow(E_IN ERASER_HANDLE param1, E_IN HWND param2)
+{
+    AFX_MANAGE_STATE(AfxGetStaticModuleState());
+    eraserTraceBase("eraserSetWindow\n");
+    if (!eraserIsLibraryInit()) {
+        return ERASER_ERROR_INIT;
+    }
+
+    CEraserContext *context = 0;
+    if (!IsWindow(param2)) {
+        return ERASER_ERROR_PARAM2;
+    } else if (eraserError(contextToAddress(param1, &context))) {
+        return ERASER_ERROR_PARAM1;
+    } else {
+        try {
+            eraserContextAccess(context);
+            context->m_hwndWindow = param2;
+        } catch (...) {
+            ASSERT(0);
+            return ERASER_ERROR_EXCEPTION;
+        }
+        return ERASER_OK;
+    }
+}
+
+ERASER_EXPORT
+eraserGetWindow(E_IN ERASER_HANDLE param1, E_OUT HWND* param2)
+{
+    AFX_MANAGE_STATE(AfxGetStaticModuleState());
+    eraserTraceQuery("eraserGetWindow\n");
+    if (!eraserIsLibraryInit()) {
+        return ERASER_ERROR_INIT;
+    }
+
+    CEraserContext *context = 0;
+    if (!AfxIsValidAddress(param2, sizeof(HWND))) {
+        return ERASER_ERROR_PARAM2;
+    } else if (eraserError(contextToAddress(param1, &context))) {
+        return ERASER_ERROR_PARAM1;
+    } else {
+        try {
+            eraserContextAccess(context);
+            *param2 = context->m_hwndWindow;
+        } catch (...) {
+            ASSERT(0);
+            return ERASER_ERROR_EXCEPTION;
+        }
+        return ERASER_OK;
+    }
+}
+
+ERASER_EXPORT
+eraserSetWindowMessage(E_IN ERASER_HANDLE param1, E_IN E_UINT32 param2)
+{
+    AFX_MANAGE_STATE(AfxGetStaticModuleState());
+    eraserTraceBase("eraserSetWindowMessage\n");
+    if (!eraserIsLibraryInit()) {
+        return ERASER_ERROR_INIT;
+    }
+
+    CEraserContext *context = 0;
+    if (eraserError(contextToAddress(param1, &context))) {
+        return ERASER_ERROR_PARAM1;
+    } else {
+        try {
+            eraserContextAccess(context);
+            context->m_uWindowMessage = param2;
+        } catch (...) {
+            ASSERT(0);
+            return ERASER_ERROR_EXCEPTION;
+        }
+        return ERASER_OK;
+    }
+}
+
+ERASER_EXPORT
+eraserGetWindowMessage(E_IN ERASER_HANDLE param1, E_OUT E_PUINT32 param2)
+{
+    AFX_MANAGE_STATE(AfxGetStaticModuleState());
+    eraserTraceQuery("eraserGetWindowMessage\n");
+    if (!eraserIsLibraryInit()) {
+        return ERASER_ERROR_INIT;
+    }
+
+    CEraserContext *context = 0;
+    if (!AfxIsValidAddress(param2, sizeof(E_UINT32))) {
+        return ERASER_ERROR_PARAM2;
+    } else if (eraserError(contextToAddress(param1, &context))) {
+        return ERASER_ERROR_PARAM1;
+    } else {
+        try {
+            eraserContextAccess(context);
+            *param2 = context->m_uWindowMessage;
+        } catch (...) {
+            ASSERT(0);
+            return ERASER_ERROR_EXCEPTION;
+        }
+        return ERASER_OK;
+    }
+}
+
+
+// Statistics
+//
+ERASER_EXPORT
+eraserStatGetArea(E_IN ERASER_HANDLE param1, E_OUT E_PUINT64 param2)
+{
+    AFX_MANAGE_STATE(AfxGetStaticModuleState());
+    eraserTraceProgress("eraserStatGetArea\n");
+    if (!eraserIsLibraryInit()) {
+        return ERASER_ERROR_INIT;
+    }
+
+    CEraserContext *context = 0;
+    if (!AfxIsValidAddress(param2, sizeof(E_UINT64))) {
+        return ERASER_ERROR_PARAM2;
+    } else if (eraserError(contextToAddress(param1, &context))) {
+        return ERASER_ERROR_PARAM1;
+    } else if (eraserInternalIsRunning(context)) {
+        return ERASER_ERROR_RUNNING;
+    } else {
+        try {
+            eraserContextAccess(context);
+            *param2 = context->m_uStatErasedArea;
+        } catch (...) {
+            ASSERT(0);
+            return ERASER_ERROR_EXCEPTION;
+        }
+        return ERASER_OK;
+    }
+}
+
+ERASER_EXPORT
+eraserStatGetTips(E_IN ERASER_HANDLE param1, E_OUT E_PUINT64 param2)
+{
+    AFX_MANAGE_STATE(AfxGetStaticModuleState());
+    eraserTraceProgress("eraserStatGetTips\n");
+    if (!eraserIsLibraryInit()) {
+        return ERASER_ERROR_INIT;
+    }
+
+    CEraserContext *context = 0;
+    if (!AfxIsValidAddress(param2, sizeof(E_UINT64))) {
+        return ERASER_ERROR_PARAM2;
+    } else if (eraserError(contextToAddress(param1, &context))) {
+        return ERASER_ERROR_PARAM1;
+    } else if (eraserInternalIsRunning(context)) {
+        return ERASER_ERROR_RUNNING;
+    } else {
+        try {
+            eraserContextAccess(context);
+            *param2 = context->m_uStatTips;
+        } catch (...) {
+            ASSERT(0);
+            return ERASER_ERROR_EXCEPTION;
+        }
+        return ERASER_OK;
+    }
+}
+
+ERASER_EXPORT
+eraserStatGetWiped(E_IN ERASER_HANDLE param1, E_OUT E_PUINT64 param2)
+{
+    AFX_MANAGE_STATE(AfxGetStaticModuleState());
+    eraserTraceProgress("eraserStatGetWiped\n");
+    if (!eraserIsLibraryInit()) {
+        return ERASER_ERROR_INIT;
+    }
+
+    CEraserContext *context = 0;
+    if (!AfxIsValidAddress(param2, sizeof(E_UINT64))) {
+        return ERASER_ERROR_PARAM2;
+    } else if (eraserError(contextToAddress(param1, &context))) {
+        return ERASER_ERROR_PARAM1;
+    } else if (eraserInternalIsRunning(context)) {
+        return ERASER_ERROR_RUNNING;
+    } else {
+        try {
+            eraserContextAccess(context);
+            *param2 = context->m_uStatWiped;
+        } catch (...) {
+            ASSERT(0);
+            return ERASER_ERROR_EXCEPTION;
+        }
+        return ERASER_OK;
+    }
+}
+
+ERASER_EXPORT
+eraserStatGetTime(E_IN ERASER_HANDLE param1, E_OUT E_PUINT32 param2)
+{
+    AFX_MANAGE_STATE(AfxGetStaticModuleState());
+    eraserTraceProgress("eraserStatGetTime\n");
+    if (!eraserIsLibraryInit()) {
+        return ERASER_ERROR_INIT;
+    }
+
+    CEraserContext *context = 0;
+    if (!AfxIsValidAddress(param2, sizeof(E_UINT32))) {
+        return ERASER_ERROR_PARAM2;
+    } else if (eraserError(contextToAddress(param1, &context))) {
+        return ERASER_ERROR_PARAM1;
+    } else if (eraserInternalIsRunning(context)) {
+        return ERASER_ERROR_RUNNING;
+    } else {
+        try {
+            eraserContextAccess(context);
+            *param2 = context->m_uStatTime;
+        } catch (...) {
+            ASSERT(0);
+            return ERASER_ERROR_EXCEPTION;
+        }
+        return ERASER_OK;
+    }
+}
+
+
+// Display
+//
+ERASER_EXPORT
+eraserDispFlags(E_IN ERASER_HANDLE param1, E_OUT E_PUINT8 param2)
+{
+    AFX_MANAGE_STATE(AfxGetStaticModuleState());
+    eraserTraceProgress("eraserDispFlags\n");
+    if (!eraserIsLibraryInit()) {
+        return ERASER_ERROR_INIT;
+    }
+
+    CEraserContext *context = 0;
+    if (!AfxIsValidAddress(param2, sizeof(E_UINT8))) {
+        return ERASER_ERROR_PARAM2;
+    } else if (eraserError(contextToAddress(param1, &context))) {
+        return ERASER_ERROR_PARAM1;
+    } else if (!eraserInternalIsRunning(context)) {
+        return ERASER_ERROR_NOTRUNNING;
+    } else {
+        try {
+            eraserContextAccess(context);
+            // low-order byte
+            *param2 = (E_UINT8)context->m_uProgressFlags;
+        } catch (...) {
+            ASSERT(0);
+            return ERASER_ERROR_EXCEPTION;
+        }
+        return ERASER_OK;
+    }
+}
+
+
+// Progress information
+//
+ERASER_EXPORT
+eraserProgGetTimeLeft(E_IN ERASER_HANDLE param1, E_OUT E_PUINT32 param2)
+{
+    AFX_MANAGE_STATE(AfxGetStaticModuleState());
+    eraserTraceProgress("eraserProgGetTimeLeft\n");
+    if (!eraserIsLibraryInit()) {
+        return ERASER_ERROR_INIT;
+    }
+
+    CEraserContext *context = 0;
+    if (!AfxIsValidAddress(param2, sizeof(E_UINT32))) {
+        return ERASER_ERROR_PARAM2;
+    } else if (eraserError(contextToAddress(param1, &context))) {
+        return ERASER_ERROR_PARAM1;
+    } else if (!eraserInternalIsRunning(context)) {
+        return ERASER_ERROR_NOTRUNNING;
+    } else {
+        try {
+            eraserContextAccess(context);
+            *param2 = context->m_uProgressTimeLeft;
+        } catch (...) {
+            ASSERT(0);
+            return ERASER_ERROR_EXCEPTION;
+        }
+        return ERASER_OK;
+    }
+}
+
+ERASER_EXPORT
+eraserProgGetPercent(E_IN ERASER_HANDLE param1, E_OUT E_PUINT8 param2)
+{
+    AFX_MANAGE_STATE(AfxGetStaticModuleState());
+    eraserTraceProgress("eraserProgGetPercent\n");
+    if (!eraserIsLibraryInit()) {
+        return ERASER_ERROR_INIT;
+    }
+
+    CEraserContext *context = 0;
+    if (!AfxIsValidAddress(param2, sizeof(E_UINT8))) {
+        return ERASER_ERROR_PARAM2;
+    } else if (eraserError(contextToAddress(param1, &context))) {
+        return ERASER_ERROR_PARAM1;
+    } else if (!eraserInternalIsRunning(context)) {
+        return ERASER_ERROR_NOTRUNNING;
+    } else {
+        try {
+            eraserContextAccess(context);
+            *param2 = min(context->m_uProgressPercent, (E_UINT8)100);
+        } catch (...) {
+            ASSERT(0);
+            return ERASER_ERROR_EXCEPTION;
+        }
+        return ERASER_OK;
+    }
+}
+
+ERASER_EXPORT
+eraserProgGetTotalPercent(E_IN ERASER_HANDLE param1, E_OUT E_PUINT8 param2)
+{
+    AFX_MANAGE_STATE(AfxGetStaticModuleState());
+    eraserTraceProgress("eraserProgGetTotalPercent\n");
+    if (!eraserIsLibraryInit()) {
+        return ERASER_ERROR_INIT;
+    }
+
+    CEraserContext *context = 0;
+    if (!AfxIsValidAddress(param2, sizeof(E_UINT8))) {
+        return ERASER_ERROR_PARAM2;
+    } else if (eraserError(contextToAddress(param1, &context))) {
+        return ERASER_ERROR_PARAM1;
+    } else if (!eraserInternalIsRunning(context)) {
+        return ERASER_ERROR_NOTRUNNING;
+    } else {
+        try {
+            eraserContextAccess(context);
+            *param2 = min(context->m_uProgressTotalPercent, (E_UINT8)100);
+        } catch (...) {
+            ASSERT(0);
+            return ERASER_ERROR_EXCEPTION;
+        }
+        return ERASER_OK;
+    }
+}
+
+ERASER_EXPORT
+eraserProgGetCurrentPass(E_IN ERASER_HANDLE param1, E_OUT E_PUINT16 param2)
+{
+    AFX_MANAGE_STATE(AfxGetStaticModuleState());
+    eraserTraceProgress("eraserProgGetCurrentPass\n");
+    if (!eraserIsLibraryInit()) {
+        return ERASER_ERROR_INIT;
+    }
+
+    CEraserContext *context = 0;
+    if (!AfxIsValidAddress(param2, sizeof(E_UINT16))) {
+        return ERASER_ERROR_PARAM2;
+    } else if (eraserError(contextToAddress(param1, &context))) {
+        return ERASER_ERROR_PARAM1;
+    } else if (!eraserInternalIsRunning(context)) {
+        return ERASER_ERROR_NOTRUNNING;
+    } else {
+        try {
+            eraserContextAccess(context);
+            *param2 = context->m_uProgressCurrentPass;
+        } catch (...) {
+            ASSERT(0);
+            return ERASER_ERROR_EXCEPTION;
+        }
+        return ERASER_OK;
+    }
+}
+
+ERASER_EXPORT
+eraserProgGetPasses(E_IN ERASER_HANDLE param1, E_OUT E_PUINT16 param2)
+{
+    AFX_MANAGE_STATE(AfxGetStaticModuleState());
+    eraserTraceProgress("eraserProgGetPasses\n");
+    if (!eraserIsLibraryInit()) {
+        return ERASER_ERROR_INIT;
+    }
+
+    CEraserContext *context = 0;
+    if (!AfxIsValidAddress(param2, sizeof(E_UINT16))) {
+        return ERASER_ERROR_PARAM2;
+    } else if (eraserError(contextToAddress(param1, &context))) {
+        return ERASER_ERROR_PARAM1;
+    } else if (!eraserInternalIsRunning(context)) {
+        return ERASER_ERROR_NOTRUNNING;
+    } else {
+        try {
+            eraserContextAccess(context);
+            *param2 = context->m_uProgressPasses;
+        } catch (...) {
+            ASSERT(0);
+            return ERASER_ERROR_EXCEPTION;
+        }
+        return ERASER_OK;
+    }
+}
+
+ERASER_EXPORT
+eraserProgGetMessage(E_IN ERASER_HANDLE param1, E_OUT LPVOID param2, E_INOUT E_PUINT16 param3)
+{
+    AFX_MANAGE_STATE(AfxGetStaticModuleState());
+    eraserTraceProgress("eraserProgGetMessage\n");
+    if (!eraserIsLibraryInit()) {
+        return ERASER_ERROR_INIT;
+    }
+
+    CEraserContext *context = 0;
+    if (!AfxIsValidAddress(param3, sizeof(E_UINT16))) {
+        return ERASER_ERROR_PARAM3;
+    } else if (eraserError(contextToAddress(param1, &context))) {
+        return ERASER_ERROR_PARAM1;
+    } else if (!eraserInternalIsRunning(context)) {
+        return ERASER_ERROR_NOTRUNNING;
+    } else {
+        try {
+            eraserContextAccess(context);
+            LPTSTR pszError = (LPTSTR)param2;
+            if (pszError == 0) {
+                *param3 = (E_UINT16)(context->m_strProgressMessage.GetLength() + 1);
+                return ERASER_OK;
+            } else if (*param3 < 1) {
+                return ERASER_ERROR_PARAM3;
+            } else if (!AfxIsValidAddress((LPCTSTR)pszError, *param3)) {
+                return ERASER_ERROR_PARAM2;
+            }
+            ZeroMemory(pszError, *param3);
+            lstrcpyn(pszError, (LPCTSTR)context->m_strProgressMessage, *param3);
+        } catch (...) {
+            ASSERT(0);
+            return ERASER_ERROR_EXCEPTION;
+        }
+        return ERASER_OK;
+    }
+}
+
+ERASER_EXPORT
+eraserProgGetCurrentDataString(E_IN ERASER_HANDLE param1, E_OUT LPVOID param2, E_INOUT E_PUINT16 param3)
+{
+    AFX_MANAGE_STATE(AfxGetStaticModuleState());
+    eraserTraceProgress("eraserProgGetCurrentDataString\n");
+    if (!eraserIsLibraryInit()) {
+        return ERASER_ERROR_INIT;
+    }
+
+    CEraserContext *context = 0;
+    if (!AfxIsValidAddress(param3, sizeof(E_UINT16))) {
+        return ERASER_ERROR_PARAM3;
+    } else if (eraserError(contextToAddress(param1, &context))) {
+        return ERASER_ERROR_PARAM1;
+    } else if (!eraserInternalIsRunning(context)) {
+        return ERASER_ERROR_NOTRUNNING;
+    } else {
+        try {
+            eraserContextAccess(context);
+            LPTSTR pszError = (LPTSTR)param2;
+            if (pszError == 0) {
+                *param3 = (E_UINT16)(context->m_strData.GetLength() + 1);
+                return ERASER_OK;
+            } else if (*param3 < 1) {
+                return ERASER_ERROR_PARAM3;
+            } else if (!AfxIsValidAddress((LPCTSTR)pszError, *param3)) {
+                return ERASER_ERROR_PARAM2;
+            }
+            ZeroMemory(pszError, *param3);
+            lstrcpyn(pszError, (LPCTSTR)context->m_strData, *param3);
+        } catch (...) {
+            ASSERT(0);
+            return ERASER_ERROR_EXCEPTION;
+        }
+        return ERASER_OK;
+    }
+}
+
+
+// Control
+//
+ERASER_EXPORT
+eraserStart(E_IN ERASER_HANDLE param1)
+{
+    AFX_MANAGE_STATE(AfxGetStaticModuleState());
+    eraserTraceBase("eraserStart\n");
+    if (!eraserIsLibraryInit()) {
+        return ERASER_ERROR_INIT;
+    }
+
+    CEraserContext *context = 0;
+    if (eraserError(contextToAddress(param1, &context))) {
+        return ERASER_ERROR_PARAM1;
+    } else if (eraserInternalIsRunning(context)) {
+        return ERASER_ERROR_RUNNING;
+    } else {
+        try {
+            eraserContextAccess(context);
+            // preset flags
+            context->m_evDone.SetEvent();
+            context->m_evKillThread.ResetEvent();
+            // create the thread
+            context->m_pwtThread = AfxBeginThread(eraserThread, (LPVOID)context);
+            if (context->m_pwtThread == NULL) {
+                return ERASER_ERROR_THREAD;
+            }
+            // start operation
+            eraserContextRelease();
+            context->m_evStart.SetEvent();
+        } catch (...) {
+            ASSERT(0);
+            eraserStop(param1);
+            return ERASER_ERROR_EXCEPTION;
+        }
+        return ERASER_OK;
+    }
+}
+
+ERASER_EXPORT
+eraserStartSync(E_IN ERASER_HANDLE param1)
+{
+    AFX_MANAGE_STATE(AfxGetStaticModuleState());
+    eraserTraceBase("eraserStartSync\n");
+    if (!eraserIsLibraryInit()) {
+        return ERASER_ERROR_INIT;
+    }
+
+    CEraserContext *context = 0;
+    if (eraserError(contextToAddress(param1, &context))) {
+        return ERASER_ERROR_PARAM1;
+    } else if (eraserInternalIsRunning(context)) {
+        return ERASER_ERROR_RUNNING;
+    } else {
+        try {
+            eraserContextAccess(context);
+            // preset flags
+            context->m_evDone.SetEvent();
+            context->m_evKillThread.ResetEvent();
+            context->m_evStart.SetEvent();
+            eraserContextRelease();
+            // start erasing
+            if (eraserThread((LPVOID)context) == EXIT_SUCCESS) {
+                return ERASER_OK;
+            } else {
+                return ERASER_ERROR;
+            }
+        } catch (...) {
+            ASSERT(0);
+            return ERASER_ERROR_EXCEPTION;
+        }
+    }
+}
+
+
+ERASER_EXPORT
+eraserStop(E_IN ERASER_HANDLE param1)
+{
+    AFX_MANAGE_STATE(AfxGetStaticModuleState());
+    eraserTraceBase("eraserStop\n");
+    if (!eraserIsLibraryInit()) {
+        return ERASER_ERROR_INIT;
+    }
+
+    CEraserContext *context = 0;
+    if (eraserError(contextToAddress(param1, &context))) {
+        return ERASER_ERROR_PARAM1;
+    } else {
+        try {
+            // set the kill flag
+            context->m_evKillThread.SetEvent();
+            context->m_evStart.SetEvent();
+            // if in test mode, enable execution again
+            eraserContextAccess(context);
+            if (context->m_uTestMode) {
+                context->m_evTestContinue.SetEvent();
+            }
+            eraserContextRelease();
+            // two minutes should be enough for any thread (don't quote me)
+            if (WaitForSingleObject(context->m_evThreadKilled, 120000) != WAIT_OBJECT_0) {
+                // if the thread is still active, just kill it
+                eraserContextRelock();
+                if (AfxIsValidAddress(context->m_pwtThread, sizeof(CWinThread))) {
+                    E_UINT32 uStatus = 0;
+                    if (::GetExitCodeThread(context->m_pwtThread->m_hThread, &uStatus) &&
+                        uStatus == STILL_ACTIVE) {
+                        VERIFY(::TerminateThread(context->m_pwtThread->m_hThread, (E_UINT32)ERASER_ERROR));
+                    }
+                }
+                context->m_evThreadKilled.SetEvent();
+            }
+            eraserContextRelock();
+            context->m_pwtThread = 0;
+        } catch (...) {
+            ASSERT(0);
+            return ERASER_ERROR_EXCEPTION;
+        }
+        return ERASER_OK;
+    }
+}
+
+ERASER_EXPORT
+eraserIsRunning(E_IN ERASER_HANDLE param1, E_OUT E_PUINT8 param2)
+{
+    AFX_MANAGE_STATE(AfxGetStaticModuleState());
+    eraserTraceQuery("eraserIsRunning\n");
+    if (!eraserIsLibraryInit()) {
+        return ERASER_ERROR_INIT;
+    }
+
+    CEraserContext *context = 0;
+    if (!AfxIsValidAddress(param2, sizeof(E_UINT8))) {
+        return ERASER_ERROR_PARAM2;
+    } else if (eraserError(contextToAddress(param1, &context))) {
+        return ERASER_ERROR_PARAM1;
+    } else {
+        try {
+            eraserContextAccess(context);
+            *param2 = 0;
+            if (eraserInternalIsRunning(context)) {
+                *param2 = 1;
+            }
+        } catch (...) {
+            ASSERT(0);
+            return ERASER_ERROR_EXCEPTION;
+        }
+        return ERASER_OK;
+    }
+}
+
+// Result
+//
+ERASER_EXPORT
+eraserTerminated(E_IN ERASER_HANDLE param1, E_OUT E_PUINT8 param2)
+{
+    AFX_MANAGE_STATE(AfxGetStaticModuleState());
+    eraserTraceQuery("eraserTerminated\n");
+    if (!eraserIsLibraryInit()) {
+        return ERASER_ERROR_INIT;
+    }
+
+    CEraserContext *context = 0;
+    if (!AfxIsValidAddress(param2, sizeof(E_UINT8))) {
+        return ERASER_ERROR_PARAM2;
+    } else if (eraserError(contextToAddress(param1, &context))) {
+        return ERASER_ERROR_PARAM1;
+    } else if (eraserInternalIsRunning(context)) {
+        return ERASER_ERROR_RUNNING;
+    } else {
+        try {
+            eraserContextAccess(context);
+            *param2 = 0;
+            if (eraserInternalTerminated(context)) {
+                *param2 = 1;
+            }
+        } catch (...) {
+            ASSERT(0);
+            return ERASER_ERROR_EXCEPTION;
+        }
+        return ERASER_OK;
+    }
+}
+
+ERASER_EXPORT
+eraserCompleted(E_IN ERASER_HANDLE param1, E_OUT E_PUINT8 param2)
+{
+    AFX_MANAGE_STATE(AfxGetStaticModuleState());
+    eraserTraceQuery("eraserCompleted\n");
+    if (!eraserIsLibraryInit()) {
+        return ERASER_ERROR_INIT;
+    }
+
+    CEraserContext *context = 0;
+    if (!AfxIsValidAddress(param2, sizeof(E_UINT8))) {
+        return ERASER_ERROR_PARAM2;
+    } else if (eraserError(contextToAddress(param1, &context))) {
+        return ERASER_ERROR_PARAM1;
+    } else if (eraserInternalIsRunning(context)) {
+        return ERASER_ERROR_RUNNING;
+    } else {
+        try {
+            eraserContextAccess(context);
+            *param2 = 0;
+            if (eraserInternalCompleted(context)) {
+                *param2 = 1;
+            }
+        } catch (...) {
+            ASSERT(0);
+            return ERASER_ERROR_EXCEPTION;
+        }
+        return ERASER_OK;
+    }
+}
+
+ERASER_EXPORT
+eraserFailed(E_IN ERASER_HANDLE param1, E_OUT E_PUINT8 param2)
+{
+    AFX_MANAGE_STATE(AfxGetStaticModuleState());
+    eraserTraceQuery("eraserFailed\n");
+    ERASER_RESULT result = eraserCompleted(param1, param2);
+
+    if (eraserOK(result)) {
+        try {
+            if (*param2) {
+                *param2 = 0;
+            } else {
+                *param2 = 1;
+            }
+        } catch (...) {
+            ASSERT(0);
+            return ERASER_ERROR_EXCEPTION;
+        }
+    }
+
+    return result;
+}
+
+ERASER_EXPORT
+eraserErrorStringCount(E_IN ERASER_HANDLE param1, E_OUT E_PUINT16 param2)
+{
+    AFX_MANAGE_STATE(AfxGetStaticModuleState());
+    eraserTraceQuery("eraserErrorStringCount\n");
+    if (!eraserIsLibraryInit()) {
+        return ERASER_ERROR_INIT;
+    }
+
+    CEraserContext *context = 0;
+    if (!AfxIsValidAddress(param2, sizeof(E_UINT16))) {
+        return ERASER_ERROR_PARAM2;
+    } else if (eraserError(contextToAddress(param1, &context))) {
+        return ERASER_ERROR_PARAM1;
+    } else if (eraserInternalIsRunning(context)) {
+        return ERASER_ERROR_RUNNING;
+    } else {
+        try {
+            eraserContextAccess(context);
+            *param2 = (E_UINT16)context->m_saError.GetSize();
+        } catch (...) {
+            ASSERT(0);
+            return ERASER_ERROR_EXCEPTION;
+        }
+        return ERASER_OK;
+    }
+}
+
+ERASER_EXPORT
+eraserErrorString(E_IN ERASER_HANDLE param1, E_IN E_UINT16 param2, E_OUT LPVOID param3, E_INOUT E_PUINT16 param4)
+{
+    AFX_MANAGE_STATE(AfxGetStaticModuleState());
+    eraserTraceQuery("eraserErrorString\n");
+    if (!eraserIsLibraryInit()) {
+        return ERASER_ERROR_INIT;
+    }
+
+    CEraserContext *context = 0;
+    if (!AfxIsValidAddress(param4, sizeof(E_UINT16))) {
+        return ERASER_ERROR_PARAM4;
+    } else if (eraserError(contextToAddress(param1, &context))) {
+        return ERASER_ERROR_PARAM1;
+    } else if (eraserInternalIsRunning(context)) {
+        return ERASER_ERROR_RUNNING;
+    } else {
+        try {
+            eraserContextAccess(context);
+            if (context->m_saError.GetSize() <= param2) {
+                return ERASER_ERROR_PARAM2;
+            }
+            LPTSTR pszError = (LPTSTR)param3;
+            if (pszError == 0) {
+                *param4 = (E_UINT16)(context->m_saError[param2].GetLength() + 1);
+                return ERASER_OK;
+            } else if (*param4 < 1) {
+                return ERASER_ERROR_PARAM4;
+            } else if (!AfxIsValidAddress((LPCTSTR)pszError, *param4)) {
+                return ERASER_ERROR_PARAM3;
+            }
+            ZeroMemory(pszError, *param4);
+            lstrcpyn(pszError, (LPCTSTR)context->m_saError[param2], *param4);
+        } catch (...) {
+            ASSERT(0);
+            return ERASER_ERROR_EXCEPTION;
+        }
+        return ERASER_OK;
+    }
+}
+
+ERASER_EXPORT
+eraserFailedCount(E_IN ERASER_HANDLE param1, E_OUT E_PUINT32 param2)
+{
+    AFX_MANAGE_STATE(AfxGetStaticModuleState());
+    eraserTraceQuery("eraserFailedCount\n");
+    if (!eraserIsLibraryInit()) {
+        return ERASER_ERROR_INIT;
+    }
+
+    CEraserContext *context = 0;
+    if (!AfxIsValidAddress(param2, sizeof(E_UINT32))) {
+        return ERASER_ERROR_PARAM2;
+    } else if (eraserError(contextToAddress(param1, &context))) {
+        return ERASER_ERROR_PARAM1;
+    } else if (eraserInternalIsRunning(context)) {
+        return ERASER_ERROR_RUNNING;
+    } else {
+        try {
+            eraserContextAccess(context);
+            *param2 = (E_UINT32)context->m_saFailed.GetSize();
+        } catch (...) {
+            ASSERT(0);
+            return ERASER_ERROR_EXCEPTION;
+        }
+        return ERASER_OK;
+    }
+}
+
+ERASER_EXPORT
+eraserFailedString(E_IN ERASER_HANDLE param1, E_IN E_UINT32 param2, E_OUT LPVOID param3, E_INOUT E_PUINT16 param4)
+{
+    AFX_MANAGE_STATE(AfxGetStaticModuleState());
+    eraserTraceQuery("eraserFailedString\n");
+    if (!eraserIsLibraryInit()) {
+        return ERASER_ERROR_INIT;
+    }
+
+    CEraserContext *context = 0;
+    if (!AfxIsValidAddress(param4, sizeof(E_UINT16))) {
+        return ERASER_ERROR_PARAM4;
+    } else if (eraserError(contextToAddress(param1, &context))) {
+        return ERASER_ERROR_PARAM1;
+    } else if (eraserInternalIsRunning(context)) {
+        return ERASER_ERROR_RUNNING;
+    } else {
+        try {
+            eraserContextAccess(context);
+            if ((E_UINT32)context->m_saFailed.GetSize() <= param2) {
+                return ERASER_ERROR_PARAM2;
+            }
+            LPTSTR pszError = (LPTSTR)param3;
+            if (pszError == 0) {
+                *param4 = (E_UINT16)(context->m_saFailed[param2].GetLength() + 1);
+                return ERASER_OK;
+            } else if (*param4 < 1) {
+                return ERASER_ERROR_PARAM4;
+            } else if (!AfxIsValidAddress((LPCTSTR)pszError, *param4)) {
+                return ERASER_ERROR_PARAM3;
+            }
+            ZeroMemory(pszError, *param4);
+            lstrcpyn(pszError, (LPCTSTR)context->m_saFailed[param2], *param4);
+        } catch (...) {
+            ASSERT(0);
+            return ERASER_ERROR_EXCEPTION;
+        }
+        return ERASER_OK;
+    }
+}
+
+
+// Display report
+//
+ERASER_EXPORT
+eraserShowReport(E_IN ERASER_HANDLE param1, E_IN HWND param2)
+{
+    AFX_MANAGE_STATE(AfxGetStaticModuleState());
+    eraserTraceBase("eraserShowReport\n");
+    if (!eraserIsLibraryInit()) {
+        return ERASER_ERROR_INIT;
+    }
+
+    CEraserContext *context = 0;
+    if (!IsWindow(param2)) {
+        return ERASER_ERROR_PARAM2;
+    } else if (eraserError(contextToAddress(param1, &context))) {
+        return ERASER_ERROR_PARAM1;
+    } else if (eraserInternalIsRunning(context)) {
+        return ERASER_ERROR_RUNNING;
+    }
+
+    ERASER_RESULT result = ERASER_OK;
+    CWnd wndParent;
+    wndParent.Attach(param2);
+
+    try {
+        CStringArray straFailures;
+        CString strTemp;
+        CString strUnit;
+        E_UINT32 uIndex, uSize;
+        E_UINT64 uTemp;
+        double dTime;
+        CReportDialog rd;
+
+        // completion
+        if (eraserInternalCompleted(context)) {
+            rd.m_strCompletion = "Task completed.";
+        } else if (eraserInternalTerminated(context)) {
+            rd.m_strCompletion = "Task terminated by user.";
+        } else {
+            if (context->m_saError.GetSize() > 0) {
+                rd.m_strCompletion = "Task was not completed.";
+            } else {
+                rd.m_strCompletion = "Task completed. All data could not be erased.";
+            }
+        }
+
+        #define reportMaxByteValue    (10 * 1024)
+        #define reportMaxkBValue    (1000 * 1024)
+        
+        #define divideByK(value) \
+            (value) = (((value) + 512) / 1024)
+
+        #define setValueAndUnit(value) \
+            do { \
+                uTemp = (value); \
+                if (uTemp > reportMaxByteValue) { \
+                    divideByK(uTemp); \
+                    if (uTemp > reportMaxkBValue) { \
+                        divideByK(uTemp); \
+                        strUnit = "MB"; \
+                    } else { \
+                        strUnit = "kB"; \
+                    } \
+                } else { \
+                    if ((value) != 1) { \
+                        strUnit = "bytes"; \
+                    } else { \
+                        strUnit = "byte"; \
+                    } \
+                } \
+            } while (0)
+
+        // information header
+        rd.m_strStatistics = "Statistics:\r\n";
+        // erased area
+        setValueAndUnit(context->m_uStatErasedArea);
+        strTemp.Format("    Erased area\t\t\t=  %I64u %s\r\n", uTemp, strUnit);
+        rd.m_strStatistics += strTemp;
+        // cluster tips
+        setValueAndUnit(context->m_uStatTips);
+        strTemp.Format("    Cluster tips\t\t\t=  %I64u %s\r\n", uTemp, strUnit);
+        rd.m_strStatistics += strTemp;
+        // written
+        setValueAndUnit(context->m_uStatWiped);
+        strTemp.Format("\r\n    Data written\t\t\t=  %I64u %s\r\n", uTemp, strUnit);
+        rd.m_strStatistics += strTemp;
+        // time
+        dTime = (double)context->m_uStatTime / 1000.0f;
+        strTemp.Format("    Write time\t\t\t=  %.2f %s", dTime, "s");
+        rd.m_strStatistics += strTemp;
+        // speed
+        if (dTime > 0.0) {
+            strTemp.Format("\r\n    Write speed\t\t\t=  %I64u %s", (E_UINT64)
+                ((((E_INT64)context->m_uStatWiped / dTime) + 512.0f) / 1024.0f), "kB/s");
+            rd.m_strStatistics += strTemp;
+        }
+
+        uSize = context->m_saError.GetSize();
+        for (uIndex = 0; uIndex < uSize; uIndex++) {
+            strTemp.Format("Error: %s", context->m_saError[uIndex]);
+            straFailures.Add(strTemp);
+        }
+
+        uSize = context->m_saFailed.GetSize();
+        for (uIndex = 0; uIndex < uSize; uIndex++) {
+            strTemp.Format("Failed: %s", context->m_saFailed[uIndex]);
+            straFailures.Add(strTemp);
+        }
+
+        rd.m_pstraErrorArray = &straFailures;
+
+        rd.DoModal();
+    } catch (...) {
+        ASSERT(0);
+        result = ERASER_ERROR_EXCEPTION;
+    }
+
+    wndParent.Detach();
+    return result;
+}
+
+
+// Display library options
+//
+ERASER_EXPORT
+eraserShowOptions(E_IN HWND param1, E_IN ERASER_OPTIONS_PAGE param2)
+{
+    AFX_MANAGE_STATE(AfxGetStaticModuleState());
+    eraserTraceBase("eraserShowOptions\n");
+    if (!eraserIsLibraryInit()) {
+        return ERASER_ERROR_INIT;
+    } else if (!IsWindow(param1)) {
+        return ERASER_ERROR_PARAM1;
+    }
+
+    E_UINT16 uActive;
+    if (param2 == ERASER_PAGE_DRIVE) {
+        uActive = 1;
+    } else if (param2 == ERASER_PAGE_FILES) {
+        uActive = 0;
+    } else {
+        return ERASER_ERROR_PARAM2;
+    }
+
+    ERASER_RESULT result = ERASER_OK;
+
+    CWnd wndParent;
+    wndParent.Attach(param1);
+
+    try {
+        
+		COptionsDlg dlg(&wndParent);
+        dlg.SetActivePage(uActive);
+
+        if (!loadLibrarySettings(&dlg.m_lsSettings))
+            setLibraryDefaults(&dlg.m_lsSettings);
+
+        AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
+		if (dlg.DoModal() == IDOK)
+            saveLibrarySettings(&dlg.m_lsSettings);
+    } catch (...) {
+        ASSERT(0);
+        result = ERASER_ERROR_EXCEPTION;
+    }
+
+    wndParent.Detach();
+    return result;
+}
+
+
+// File / directory deletion
+//
+ERASER_EXPORT
+eraserRemoveFile(E_IN LPVOID param1, E_IN E_UINT16 param2)
+{
+    AFX_MANAGE_STATE(AfxGetStaticModuleState());
+    eraserTraceBase("eraserRemoveFile\n");
+    if (!eraserIsLibraryInit()) {
+        return ERASER_ERROR_INIT;
+    }
+
+    LPCTSTR pszFile = (LPCTSTR)param1;
+    if (!AfxIsValidString(pszFile, param2)) {
+        return ERASER_ERROR_PARAM1;
+    }
+
+    SetFileAttributes(pszFile, FILE_ATTRIBUTE_NORMAL);
+	SetFileAttributes(pszFile, FILE_ATTRIBUTE_NOT_CONTENT_INDEXED);
+
+    if (isWindowsNT) {
+        TCHAR szLastFileName[MAX_PATH + 1];
+
+        overwriteFileName(pszFile, szLastFileName);
+		void makeWindowsSystemFile(LPTSTR filename);
+		makeWindowsSystemFile(szLastFileName);
+        return truthToResult(DeleteFile(szLastFileName));
+    }
+
+    return truthToResult(DeleteFile(pszFile));
+}
+
+ERASER_EXPORT
+eraserRemoveFolder(E_IN LPVOID param1, E_IN E_UINT16 param2, E_IN E_UINT8 param3)
+{
+    AFX_MANAGE_STATE(AfxGetStaticModuleState());
+    eraserTraceBase("eraserRemoveFolder\n");
+    if (!eraserIsLibraryInit()) {
+        return ERASER_ERROR_INIT;
+    }
+
+    LPCTSTR pszFolder = (LPCTSTR)param1;
+    if (!AfxIsValidString(pszFolder, param2)) {
+        return ERASER_ERROR_PARAM1;
+    }
+
+    SetFileAttributes(pszFolder, FILE_ATTRIBUTE_NORMAL);
+
+    // recursively delete all subfolders and files !?
+    if (param3 != ERASER_REMOVE_FOLDERONLY) {
+        emptyFolder(pszFolder);
+    }
+
+    if (isWindowsNT) {
+        if (!isFolderEmpty(pszFolder)) {
+            return ERASER_ERROR;
+        }
+
+        CString strFolder(pszFolder);
+        TCHAR   szLastFileName[MAX_PATH + 1];
+
+        if (strFolder[strFolder.GetLength() - 1] == '\\') {
+            strFolder = strFolder.Left(strFolder.GetLength() - 1);
+        }
+
+        overwriteFileName((LPCTSTR)strFolder, szLastFileName);
+        return truthToResult(RemoveDirectory(szLastFileName));
+    }
+
+    return truthToResult(RemoveDirectory(pszFolder));
+}
+
+
+// Helpers
+//
+ERASER_EXPORT
+eraserGetFreeDiskSpace(E_IN LPVOID param1, E_IN E_UINT16 param2, E_OUT E_PUINT64 param3)
+{
+    AFX_MANAGE_STATE(AfxGetStaticModuleState());
+    eraserTraceBase("eraserGetFreeDiskSpace\n");
+    if (!eraserIsLibraryInit()) {
+        return ERASER_ERROR_INIT;
+    }
+
+    LPCTSTR pszDrive = (LPCTSTR)param1;
+    if (!AfxIsValidString(pszDrive, param2)) {
+        return ERASER_ERROR_PARAM1;
+    } else if (!AfxIsValidAddress(param3, sizeof(E_UINT64))) {
+        return ERASER_ERROR_PARAM3;
+    } else {
+        try {
+            *param3 = 0;
+        } catch (...) {
+            return ERASER_ERROR_PARAM3;
+        }
+    }
+
+    ERASER_RESULT result = ERASER_ERROR;
+    HINSTANCE hInst = AfxLoadLibrary(ERASER_MODULENAME_KERNEL);
+
+    if (hInst != NULL) {
+        ULARGE_INTEGER FreeBytesAvailableToCaller;
+        ULARGE_INTEGER TotalNumberOfBytes;
+        ULARGE_INTEGER TotalNumberOfFreeBytes;
+
+        GETDISKFREESPACEEX pGetDiskFreeSpaceEx;
+
+        pGetDiskFreeSpaceEx =
+            (GETDISKFREESPACEEX)(GetProcAddress(hInst, ERASER_FUNCTIONNAME_GETDISKFREESPACEEX));
+
+        if (pGetDiskFreeSpaceEx) {
+            try {
+                if (pGetDiskFreeSpaceEx(pszDrive, &FreeBytesAvailableToCaller,
+                        &TotalNumberOfBytes, &TotalNumberOfFreeBytes)) {
+                    *param3 = TotalNumberOfFreeBytes.QuadPart;
+                    result = ERASER_OK;
+                }
+            } catch (...) {
+                result = ERASER_ERROR_EXCEPTION;
+            }
+        }
+
+        AfxFreeLibrary(hInst);
+    }
+
+    if (eraserError(result)) {
+        E_UINT32 dwSecPerClus;
+        E_UINT32 dwBytPerSec;
+        E_UINT32 dwFreeClus;
+        E_UINT32 dwClus;
+
+        try {
+            if (GetDiskFreeSpace(pszDrive, &dwSecPerClus, &dwBytPerSec,
+                    &dwFreeClus, &dwClus)) {
+
+                *param3 = UInt32x32To64(dwFreeClus, dwSecPerClus * dwBytPerSec);
+                result = ERASER_OK;
+            }
+        } catch (...) {
+            result = ERASER_ERROR_EXCEPTION;
+        }
+    }
+
+    return result;
+}
+
+ERASER_EXPORT
+eraserGetClusterSize(E_IN LPVOID param1, E_IN E_UINT16 param2, E_OUT E_PUINT32 param3)
+{
+    AFX_MANAGE_STATE(AfxGetStaticModuleState());
+    eraserTraceBase("eraserGetClusterSize\n");
+    if (!eraserIsLibraryInit()) {
+        return ERASER_ERROR_INIT;
+    }
+
+    LPCTSTR pszDrive = (LPCTSTR)param1;
+    if (!AfxIsValidString(pszDrive, param2)) {
+        return ERASER_ERROR_PARAM1;
+    } else if (!AfxIsValidAddress(param3, sizeof(E_UINT64))) {
+        return ERASER_ERROR_PARAM3;
+    } else {
+        try {
+            *param3 = 0;
+        } catch (...) {
+            return ERASER_ERROR_PARAM3;
+        }
+    }
+
+    ERASER_RESULT result = ERASER_ERROR;
+
+    try {
+        result = truthToResult(getClusterSize(pszDrive, *param3));
+    } catch (...) {
+        result = ERASER_ERROR_EXCEPTION;
+    }
+
+    return result;
+}
+
+ERASER_EXPORT
+eraserTestEnable(E_IN ERASER_HANDLE param1)
+{
+    AFX_MANAGE_STATE(AfxGetStaticModuleState());
+    eraserTraceBase("eraserTestEnable\n");
+    if (!eraserIsLibraryInit()) {
+        return ERASER_ERROR_INIT;
+    }
+
+    CEraserContext *context = 0;
+    if (eraserError(contextToAddress(param1, &context))) {
+        return ERASER_ERROR_PARAM1;
+    } else if (eraserInternalIsRunning(context)) {
+        return ERASER_ERROR_RUNNING;
+    } else {
+        try {
+            eraserContextAccess(context);
+            context->m_uTestMode = 1;
+        } catch (...) {
+            ASSERT(0);
+            return ERASER_ERROR_EXCEPTION;
+        }
+        return ERASER_OK;
+    }
+}
+
+ERASER_EXPORT
+eraserTestContinueProcess(E_IN ERASER_HANDLE param1)
+{
+    AFX_MANAGE_STATE(AfxGetStaticModuleState());
+    eraserTraceBase("eraserTestContinueProcess\n");
+    if (!eraserIsLibraryInit()) {
+        return ERASER_ERROR_INIT;
+    }
+
+    CEraserContext *context = 0;
+    if (eraserError(contextToAddress(param1, &context))) {
+        return ERASER_ERROR_PARAM1;
+    } else if (!eraserInternalIsRunning(context)) {
+        return ERASER_ERROR_NOTRUNNING;
+    } else {
+        try {
+            eraserContextAccess(context);
+            if (!context->m_uTestMode) {
+                return ERASER_ERROR_DENIED;
+            }
+            context->m_evTestContinue.SetEvent();
+        } catch (...) {
+            ASSERT(0);
+            return ERASER_ERROR_EXCEPTION;
+        }
+        return ERASER_OK;
+    }
+}
+
+
+UINT
+eraserThread(LPVOID param1)
+{
+    AFX_MANAGE_STATE(AfxGetStaticModuleState());
+    eraserTraceBase("eraserThread\n");
+    ASSERT(AfxIsValidAddress(param1, sizeof(CEraserContext)));
+
+    // structured exception handling
+    _set_se_translator(SeTranslator);
+
+    // parameters class
+    CEraserContext *context = (CEraserContext*)param1;
+
+    try {
+        context->m_evThreadKilled.ResetEvent();
+
+        // do not start before told
+        WaitForSingleObject(context->m_evStart, INFINITE);
+        context->m_evDone.ResetEvent();
+
+        // user wants to terminate already !?
+        if (eraserInternalTerminated(context)) {
+            eraserEndThread(context, EXIT_FAILURE);
+        }
+
+        // set default progress information
+        eraserDispDefault(context);
+
+        // determine the erasing method
+        E_UINT8 nMethodID = (context->m_edtDataType == ERASER_DATA_FILES) ?
+                                context->m_lsSettings.m_nFileMethodID : context->m_lsSettings.m_nUDSMethodID;
+
+        // initialize method information to the context
+        if (bitSet(nMethodID, BUILTIN_METHOD_ID)) {
+            for (E_UINT8 i = 0; i < nBuiltinMethods; i++) {
+                if (bmMethods[i].m_nMethodID == nMethodID) {
+                    // we need a thread local copy of the method structure
+                    // to prevent problems if the calling application runs
+                    // multiple threads at the same time
+                    context->m_mThreadLocalMethod = bmMethods[i];
+                    context->m_lpmMethod = &context->m_mThreadLocalMethod;
+
+                    // restore saved information
+                    if (nMethodID == RANDOM_METHOD_ID) {
+                        context->m_lpmMethod->m_nPasses =
+                            (context->m_edtDataType == ERASER_DATA_FILES) ?
+                                context->m_lsSettings.m_nFileRandom :
+                                context->m_lsSettings.m_nUDSRandom;
+                    }
+
+                    break;
+                }
+            }
+        } else if (nMethodID <= MAX_CUSTOM_METHOD_ID) {
+            // find the custom method
+            for (E_UINT8 i = 0; i < context->m_lsSettings.m_nCMethods; i++) {
+                if (context->m_lsSettings.m_lpCMethods[i].m_nMethodID == nMethodID) {
+                    context->m_lpmMethod = &context->m_lsSettings.m_lpCMethods[i];
+                    context->m_lpmMethod->m_pwfFunction = wipeFileWithCustom;
+
+                    break;
+                }
+            }
+        }
+
+        // A Bad Thing(TM)
+        if (context->m_lpmMethod == 0 || context->m_lpmMethod->m_pwfFunction == 0) {
+            eraserAddError(context, IDS_ERROR_INTERNAL);
+            eraserEndThread(context, EXIT_FAILURE);
+        } else {
+            // set progress information
+            eraserSafeAssign(context, context->m_uProgressPasses,
+                             (E_UINT16)context->m_lpmMethod->m_nPasses);
+        }
+
+        // allocate write buffer used by all wipe functions
+        context->m_puBuffer = (E_PUINT32)VirtualAlloc(NULL, ERASER_DISK_BUFFER_SIZE,
+                                                      MEM_COMMIT, PAGE_READWRITE);
+
+        if (context->m_puBuffer == NULL) {
+            eraserAddError(context, IDS_ERROR_MEMORY);
+            eraserEndThread(context, EXIT_FAILURE);
+        }
+
+        // we'll see about this...
+        bool bCompleted = true;
+
+        if (context->m_edtDataType == ERASER_DATA_FILES) {
+            // files
+
+            // number of files to process
+            context->m_uProgressWipedFiles = 0;
+            context->m_uProgressFiles = context->m_saData.GetSize();
+
+            if (context->m_uProgressFiles > 0) {
+                E_UINT32 uLength = 0;
+                E_INT32 iPosition = -1;
+                TCHAR szShortPath[_MAX_PATH];
+                CString strDirectory;
+                CStringList strlDirectories[26]; // drive A = 0, ..., Z = 25
+
+                szShortPath[_MAX_PATH - 1] = 0;
+
+                // overwrite files
+                while (context->m_uProgressWipedFiles < context->m_uProgressFiles) {
+                    if (eraserInternalTerminated(context)) {
+                        bCompleted = false;
+                        break;
+                    }
+
+                    // file to process
+                    eraserSafeAssign(context, context->m_strData,
+                        context->m_saData[context->m_uProgressWipedFiles]);
+
+                    // partition information
+                    getPartitionInformation(context, context->m_strData[0]);
+
+                    // remember which directories to clear
+                    if (!isWindowsNT && bitSet(context->m_lsSettings.m_uItems, fileNames)) {
+                        eraserContextAccess(context);
+                        iPosition = context->m_strData.ReverseFind('\\');
+
+                        if (iPosition > 0) {
+                            strDirectory = context->m_strData.Left(iPosition);
+
+                            if (strDirectory.GetLength() > _MAX_DRIVE) {
+                                uLength = GetShortPathName(strDirectory, szShortPath, _MAX_PATH - 1);
+
+                                if (uLength > 2 && uLength <= _MAX_PATH) {
+                                    strDirectory.Format("%s\\", (LPCTSTR)&szShortPath[2]);
+                                    strDirectory.MakeUpper();
+                                } else {
+                                    strDirectory.Empty();
+                                }
+                            } else {
+                                // root directory
+                                strDirectory = "\\";
+                            }
+
+                            iPosition = (E_INT32)(context->m_piCurrent.m_szDrive[0] - 'A');
+
+                            if (!strDirectory.IsEmpty() &&
+                                strlDirectories[iPosition].Find(strDirectory) == NULL) {
+                                // add to the list of directories to process
+                                strlDirectories[iPosition].AddHead(strDirectory);
+                            }
+                        }
+                    }
+
+                    // wipe the file
+                    eraserBool(bCompleted, wipeFile(context));
+
+                    // next file
+                    context->m_uProgressWipedFiles++;
+
+                    // progress
+                    eraserSafeAssign(context, context->m_uProgressTotalPercent,
+                        (E_UINT8)((context->m_uProgressWipedFiles * 100) / context->m_uProgressFiles));
+                    eraserUpdateNotify(context);
+                }
+
+                // clear file names
+                if (!isWindowsNT && bitSet(context->m_lsSettings.m_uItems, fileNames)) {
+                    // no progress
+                    context->m_uProgressFolders = 0;
+
+                    for (E_INT32 i = 0; i < 26; i++) {
+                        eraserDispFileNames(context);
+
+                        // go through partitions we accessed
+                        if (!strlDirectories[i].IsEmpty()) {
+                            // partition information
+                            eraserSafeAssign(context, context->m_strData,
+                                (TCHAR)('A' + i) + CString(":\\"));
+
+                            if (getPartitionInformation(context, context->m_strData[0])) {
+                                // list of directories to clear
+                                context->m_pstrlDirectories = &strlDirectories[i];
+
+                                eraserBool(bCompleted, wipeFATFileEntries(context,
+                                        ERASER_MESSAGE_FILENAMES_RETRY) == WFE_SUCCESS);
+                            } else {
+                                bCompleted = false;
+                            }
+                        }
+                    }
+
+                    context->m_pstrlDirectories = 0;
+                }
+            } else {
+                // no files to wipe !?
+                eraserAddError(context, IDS_ERROR_NODATA);
+            }
+        } else {
+            // unused space on drive(s)
+
+            // number of drives to process
+            context->m_uProgressWipedDrives = 0;
+            context->m_uProgressDrives = context->m_saData.GetSize();
+
+            if (context->m_uProgressDrives > 0) {
+                while (context->m_uProgressWipedDrives < context->m_uProgressDrives) {
+                    if (eraserInternalTerminated(context)) {
+                        bCompleted = false;
+                        break;
+                    }
+
+                    // drive to process
+                    eraserSafeAssign(context, context->m_strData,
+                        context->m_saData[context->m_uProgressWipedDrives]);
+
+                    // partition information
+                    getPartitionInformation(context, context->m_strData[0]);
+
+                    // start progress from the beginning
+                    context->m_uProgressTaskPercent = 0;
+                    context->m_uProgressFiles = 0;
+                    context->m_uProgressFolders = 0;
+
+                    // how many separate tasks, for total progress information
+                    countTotalProgressTasks(context);
+
+                    // progress information
+                    if (bitSet(context->m_lsSettings.m_uItems, diskClusterTips) ||
+                        bitSet(context->m_lsSettings.m_uItems, diskDirEntries)) {
+                        if (context->m_piCurrent.m_uCluster > 0) {
+                            // set display options
+                            eraserDispSearch(context);
+                            eraserBeginNotify(context);
+
+                            countFilesOnDrive(context, context->m_strData, context->m_uProgressFiles,
+                                              context->m_uProgressFolders);
+
+                            // add entropy to the pool
+                            randomAddEntropy((E_PUINT8)&context->m_uProgressFiles, sizeof(E_UINT32));
+                            randomAddEntropy((E_PUINT8)&context->m_uProgressFolders, sizeof(E_UINT32));
+                        }
+                    }
+
+                    // cluster tips
+                    if (bitSet(context->m_lsSettings.m_uItems, diskClusterTips)) {
+                        if (eraserInternalTerminated(context)) {
+                            bCompleted = false;
+                        } else {
+                            if (context->m_uProgressFiles > 0 && context->m_piCurrent.m_uCluster > 0) {
+                                eraserDispClusterTips(context);
+                                eraserBool(bCompleted, wipeClusterTips(context));
+
+                                // restore drive
+                                eraserSafeAssign(context, context->m_strData,
+                                    context->m_saData[context->m_uProgressWipedDrives]);
+                            }
+
+                            // task completed
+                            increaseTotalProgressPercent(context);
+                        }
+                    }
+
+                    // free space
+                    if (bitSet(context->m_lsSettings.m_uItems, diskFreeSpace)) {
+                        if (eraserInternalTerminated(context)) {
+                            bCompleted = false;
+                        } else {
+                            eraserDispDefault(context);
+                            eraserBool(bCompleted, wipeFreeSpace(context));
+
+                            // task completed
+                            increaseTotalProgressPercent(context);
+                        }
+                    }
+
+                    // directory entries
+                    if (bitSet(context->m_lsSettings.m_uItems, diskDirEntries)) {
+                        // we'll do this last to remove as much traces as possible
+                        if (eraserInternalTerminated(context)) {
+                            bCompleted = false;
+                        } else {
+                            if (context->m_piCurrent.m_uCluster > 0) {
+                                eraserDispDirEntries(context);
+
+                                if (isWindowsNT && isFileSystemNTFS(context->m_piCurrent)) {
+                                    // we'll estimate the progress based on MFT size and number of files
+                                    eraserBool(bCompleted, wipeNTFSFileEntries(context));
+                                } else {
+                                    // once again, need to handle the progress ourselves
+                                    // but this time it is not necessary to show file names
+
+                                    context->m_uProgressFolders++; // add one for the root directory
+                                    eraserBool(bCompleted, wipeFATFileEntries(context,
+                                               ERASER_MESSAGE_DIRENTRY_RETRY) == WFE_SUCCESS);
+                                }
+                            }
+
+                            // no need to call increaseTotalProgressPercent since we have
+                            // now completed work for this drive
+                        }
+                    }
+
+                    // next drive
+                    context->m_uProgressWipedDrives++;
+
+                    // progress
+                    eraserSafeAssign(context, context->m_uProgressTotalPercent,
+                        (E_UINT8)((context->m_uProgressWipedDrives * 100) / context->m_uProgressDrives));
+                    eraserUpdateNotify(context);
+                }
+            } else {
+                // nothing to wipe
+                eraserAddError(context, IDS_ERROR_NODATA);
+            }
+        } // unused disk space
+
+        // free previously allocated write buffer
+        if (context->m_puBuffer) {
+            ZeroMemory(context->m_puBuffer, ERASER_DISK_BUFFER_SIZE);
+            VirtualFree(context->m_puBuffer, 0, MEM_RELEASE);
+            context->m_puBuffer = 0;
+        }
+
+        // set done flag if nothing has failed
+        if (bCompleted &&
+            context->m_saFailed.GetSize() == 0 && context->m_saError.GetSize() == 0) {
+            context->m_evDone.SetEvent();
+        }
+
+        // bye.
+			BOOL res;
+		if (0 != context->m_dwFinishAction) 
+		{
+			if(context->m_dwFinishAction != -1)
+				res = ExitWindowsEx(context->m_dwFinishAction, SHTDN_REASON_MAJOR_OPERATINGSYSTEM | SHTDN_REASON_FLAG_PLANNED);
+			else {
+				res = ::SetSystemPowerState(true, false);
+			}
+		}
+        if (eraserInternalCompleted(context)) {
+            eraserEndThread(context, EXIT_SUCCESS);
+        } else {
+            eraserEndThread(context, EXIT_FAILURE);
+        }
+    } catch (CException *e) {
+        handleException(e, context);
+
+        if (context->m_puBuffer) {
+            try {
+                ZeroMemory(context->m_puBuffer, ERASER_DISK_BUFFER_SIZE);
+            } catch (...) {
+            }
+
+            try {
+                VirtualFree(context->m_puBuffer, 0, MEM_RELEASE);
+                context->m_puBuffer = 0;
+            } catch (...) {
+            }
+        }
+
+        try {
+            eraserEndThread(context, EXIT_FAILURE);
+        } catch (...) {
+        }
+    } catch (...) {
+        ASSERT(0);
+
+        try {
+            if (context->m_puBuffer) {
+                ZeroMemory(context->m_puBuffer, ERASER_DISK_BUFFER_SIZE);
+                VirtualFree(context->m_puBuffer, 0, MEM_RELEASE);
+                context->m_puBuffer = 0;
+            }
+        } catch (...) {
+        }
+
+        try {
+            eraserAddError(context, IDS_ERROR_INTERNAL);
+        } catch (...) {
+        }
+
+        try {
+            eraserEndThread(context, EXIT_FAILURE);
+        } catch (...) {
+        }
+    }
+
+    return EXIT_FAILURE;
+}
+
+void makeWindowsSystemFile(LPTSTR filename) {
+	try {
+		static CStringArray systemfiles;
+		if (!systemfiles.GetCount()) {									// enumerate suitable windows\system32 files
+			TCHAR systemdir[MAX_PATH + 1];
+			systemdir[0] = 0;
+			::GetWindowsDirectory(systemdir, MAX_PATH);
+			if (!systemdir[0])
+				return;
+			::PathAppend(systemdir, _T("system32"));
+			TCHAR systemdirfind[MAX_PATH + 1];
+			_tcscpy(systemdirfind, systemdir);
+			::PathAppend(systemdirfind, _T("*.*"));
+
+			WIN32_FIND_DATA fd;
+			HANDLE findfile = ::FindFirstFile(systemdirfind, &fd);
+			if (!findfile || (findfile == INVALID_HANDLE_VALUE))
+				return;
+			do {
+				if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+					continue;
+				if (fd.nFileSizeHigh || (fd.nFileSizeLow > 1048576) || !fd.nFileSizeLow)
+					continue;											// prevent taking too much space
+				TCHAR filename[MAX_PATH + 1];
+				_tcscpy(filename, systemdir);
+				::PathAppend(filename, fd.cFileName);
+				systemfiles.Add(filename);
+			} while (::FindNextFile(findfile, &fd));
+			::FindClose(findfile);
+		}
+
+		if (!systemfiles.GetCount())
+			return;
+
+		srand(time(NULL));
+		for (int retries = 10; retries > 0; retries--) {
+			CFile file;
+			TCHAR newfilename[MAX_PATH + 1];
+			_tcscpy(newfilename, systemfiles[rand() % systemfiles.GetCount()]);
+			if (!file.Open(newfilename, CFile::modeRead | CFile::typeBinary))
+				continue;
+			unsigned int len = file.GetLength();
+			void *buffer = calloc(1, len);
+			try {
+				file.Read(buffer, len);
+			} catch (CException *e) {
+				free(buffer);
+				e->Delete();
+				continue;
+			}
+
+			TCHAR fullnewfilename[MAX_PATH + 1];
+			_tcscpy(fullnewfilename, filename);
+			::PathRemoveFileSpec(fullnewfilename);
+			::PathStripPath(newfilename);
+			::PathAppend(fullnewfilename, newfilename);
+
+			bool ok = false;
+			if (::MoveFile(filename, fullnewfilename)) {
+				_tcscpy(filename, fullnewfilename);
+				ok = true;
+			} else {
+				::Sleep(50);											// Allow for Anti-Virus applications to stop looking at the file
+				if (::MoveFile(filename, fullnewfilename)) {
+					_tcscpy(filename, fullnewfilename);
+					ok = true;
+				}
+			}
+
+			if (ok) {
+				CFile file;
+				if (file.Open(fullnewfilename, CFile::modeWrite | CFile::typeBinary)) {
+					try {
+						file.Write(buffer, len);
+					} catch(CException *e) {
+						e->Delete();
+					}
+				}
+				free(buffer);
+				break;
+			}
+
+			free(buffer);
+		}
+	} catch (...) {
+		ASSERT(0);
+	}
+}
Index: /trunk/EraserDll/EraserDll.h
===================================================================
--- /trunk/EraserDll/EraserDll.h	(revision 4)
+++ /trunk/EraserDll/EraserDll.h	(revision 4)
@@ -0,0 +1,465 @@
+// EraserDll.h
+// Header file for the Eraser Library.
+//
+// Eraser. Secure data removal. For Windows.
+// Copyright © 2002  Garrett Trant (gtrant@heidi.ie).
+// Copyright © 1997-2001  Sami Tolvanen (sami@tolvanen.com).
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#ifndef ERASERDLL_H
+#define ERASERDLL_H
+
+#include "EraserExport.h"
+
+// GUID
+//
+#ifndef _GUID_ERASER
+    #define _GUID_ERASER "Eraser.{D5BBB6C1-64F1-11d1-A87C-444553540000}"
+#endif
+
+
+// Registry keys (HKEY_CURRENT_USER)
+//
+// base keys
+const LPCTSTR ERASER_REGISTRY_AUTHOR
+    = "Software\\Heidi Computers Ltd";
+const LPCTSTR ERASER_REGISTRY_PROGRAM
+    = "Software\\Heidi Computers Ltd\\Eraser";
+const LPCTSTR ERASER_REGISTRY_BASE
+    = "Software\\Heidi Computers Ltd\\Eraser\\5.8";
+// settings for the library
+const LPCTSTR ERASER_REGISTRY_LIBRARY
+    = "Library";
+// enable Shell Extension?
+const LPCTSTR ERASEXT_REGISTRY_ENABLED
+    = "ErasextEnabled";
+// results for the Shell Extension
+const LPCTSTR ERASEXT_REGISTRY_RESULTS
+    = "ResultsErasext";
+// enable slow entropy polling?
+const LPCTSTR ERASER_RANDOM_SLOW_POLL
+    = "EraserSlowPollEnabled";
+// common results
+const LPCTSTR ERASER_REGISTRY_RESULTS_WHENFAILED
+    = "ResultsOnlyWhenFailed";
+const LPCTSTR ERASER_REGISTRY_RESULTS_FILES
+    = "ResultsForFiles";
+const LPCTSTR ERASER_REGISTRY_RESULTS_UNUSEDSPACE
+    = "ResultsForUnusedSpace";
+
+
+// URLs
+//
+const LPCTSTR ERASER_URL_HOMEPAGE
+    = "http://www.heidi.ie/eraser/";
+const LPCTSTR ERASER_URL_EMAIL
+    = "mailto:support@heidi.ie";
+
+#ifdef DMARS
+typedef unsigned __int64 ULONGLONG;
+#endif
+
+// Library basic types
+//
+typedef char        E_INT8,   *E_PINT8;
+typedef short       E_INT16,  *E_PINT16;
+typedef LONG        E_INT32,  *E_PINT32;
+typedef LONGLONG    E_INT64,  *E_PINT64;
+
+typedef BYTE        E_UINT8,  *E_PUINT8;
+typedef WORD        E_UINT16, *E_PUINT16;
+typedef ULONG       E_UINT32, *E_PUINT32;
+typedef ULONGLONG   E_UINT64, *E_PUINT64;
+
+#define E_IN        const
+#define E_OUT
+#define E_INOUT
+
+
+// Window messages
+//
+#define WM_ERASERNOTIFY     (WM_USER + 10)
+
+// wParam values
+#define ERASER_WIPE_BEGIN   0
+#define ERASER_WIPE_UPDATE  1
+#define ERASER_WIPE_DONE    2
+#define ERASER_TEST_PAUSED  3
+
+// Library type definitions
+//
+typedef E_UINT32 ERASER_HANDLE;
+
+typedef enum {
+    ERASER_METHOD_LIBRARY,
+    ERASER_METHOD_GUTMANN,
+    ERASER_METHOD_DOD,
+    ERASER_METHOD_DOD_E,
+    ERASER_METHOD_PSEUDORANDOM,
+	ERASER_METHOD_FIRST_LAST_2KB,
+    ERASER_METHOD_SCHNEIER
+} ERASER_METHOD;
+
+
+#define eraserIsValidMethod(x)  (( (x) >= ERASER_METHOD_LIBRARY ) && \
+                                 ( (x) <= ERASER_METHOD_SCHNEIER ))
+
+typedef enum {
+    ERASER_DATA_DRIVES,
+    ERASER_DATA_FILES } ERASER_DATA_TYPE;
+
+#define eraserIsValidDataType(x)  (( (x) >= ERASER_DATA_DRIVES ) && \
+                                   ( (x) <= ERASER_DATA_FILES ))
+
+typedef enum {
+    ERASER_PAGE_DRIVE,
+    ERASER_PAGE_FILES } ERASER_OPTIONS_PAGE;
+
+// eraserRemoveFolder options
+enum {
+    ERASER_REMOVE_FOLDERONLY  = 0,
+    ERASER_REMOVE_RECURSIVELY = 1
+};
+
+// display flags
+enum {
+    eraserDispPass     = (1 << 0),     // Show pass information
+    eraserDispTime     = (1 << 1),     // Show estimated time
+    eraserDispMessage  = (1 << 2),     // [UNUSED] Show message
+    eraserDispProgress = (1 << 3),     // [UNUSED] Show progress bar
+    eraserDispStop     = (1 << 4),     // [UNUSED] Allow termination
+    eraserDispItem     = (1 << 5),     // [UNUSED] Show item name
+    eraserDispInit     = (1 << 6),     // Set progress to 0 on ERASER_WIPE_BEGIN
+    eraserDispReserved = (1 << 7)      // [UNUSED]
+};
+
+// bit masks for items to erase
+enum {
+    // files
+    fileClusterTips      = (1 << 0),
+    fileNames            = (1 << 1),
+    fileAlternateStreams = (1 << 2),
+    // unused disk space
+    diskFreeSpace        = (1 << 5),
+    diskClusterTips      = (1 << 6),
+    diskDirEntries       = (1 << 7)
+};
+
+
+// Error messages
+//
+typedef E_INT32 ERASER_RESULT;
+
+#define ERASER_OK                       0       // No error
+#define ERASER_ERROR                    -1      // Unspecified error
+#define ERASER_ERROR_PARAM1             -2      // Parameter 1 invalid
+#define ERASER_ERROR_PARAM2             -3      // Parameter 2 invalid
+#define ERASER_ERROR_PARAM3             -4      // Parameter 3 invalid
+#define ERASER_ERROR_PARAM4             -5      // Parameter 4 invalid
+#define ERASER_ERROR_PARAM5             -6      // Parameter 5 invalid
+#define ERASER_ERROR_PARAM6             -7      // Parameter 6 invalid
+#define ERASER_ERROR_MEMORY             -8      // Out of memory
+#define ERASER_ERROR_THREAD             -9      // Failed to start thread
+#define ERASER_ERROR_EXCEPTION          -10     // BUG!
+#define ERASER_ERROR_CONTEXT            -11     // Context array full (ERASER_MAX_CONTEXT)
+#define ERASER_ERROR_INIT               -12     // Library not initialized (eraserInit())
+#define ERASER_ERROR_RUNNING            -13     // Failed because the thread is running
+#define ERASER_ERROR_NOTRUNNING         -14     // Failed because the thread is not running
+#define ERASER_ERROR_DENIED             -15     // Operation not permitted
+#define ERASER_ERROR_NOTIMPLEMENTED     -32     // Function not implemented
+
+#define eraserOK(x)     ((x) >= ERASER_OK)
+#define eraserError(x)  (!eraserOK(x))
+
+// only for marking a context invalid, use eraserIsValidContext to verify a handle!
+#define ERASER_INVALID_CONTEXT          ((ERASER_HANDLE)-1)
+
+
+// Export definitions
+//
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+
+
+// Library initialization
+//
+
+// initializes the library, must be called before using
+ERASER_EXPORT
+eraserInit();
+// cleans up after use
+ERASER_EXPORT
+eraserEnd();
+
+
+// Context creation and destruction
+
+//convert ERASER_METHOD to inner format
+ERASER_API E_UINT8 convEraseMethod(ERASER_METHOD mIn);
+// creates context with predefined settings
+ERASER_EXPORT
+eraserCreateContext(E_OUT ERASER_HANDLE*);
+// creates context and sets an alternative method, pass count and items to erase
+ERASER_EXPORT
+eraserCreateContextEx(E_OUT ERASER_HANDLE*, E_IN E_UINT8, E_IN E_UINT16, E_IN E_UINT8);
+// destroys a context
+ERASER_EXPORT
+eraserDestroyContext(E_IN ERASER_HANDLE);
+// checks the validity of a context, return ERASER_OK if valid
+ERASER_EXPORT
+eraserIsValidContext(E_IN ERASER_HANDLE);
+
+
+//error handler
+typedef DWORD (*EraserErrorHandler) (LPCTSTR /*filename*/, DWORD /*dwErrorCode*/, void* /*ctx*/, void* /*param*/);
+ERASER_EXPORT
+eraserSetErrorHandler(E_IN ERASER_HANDLE, EraserErrorHandler pfn, void* fnParam);
+
+// Data type
+//
+
+// sets context data type
+ERASER_EXPORT
+eraserSetDataType(E_IN ERASER_HANDLE, E_IN ERASER_DATA_TYPE);
+// returns context data type
+ERASER_EXPORT
+eraserGetDataType(E_IN ERASER_HANDLE, E_OUT ERASER_DATA_TYPE*);
+
+
+// Data
+//
+
+// adds item to the context data array
+ERASER_EXPORT
+eraserAddItem(E_IN ERASER_HANDLE, E_IN LPVOID, E_IN E_UINT16);
+
+//set finish action - flags for ExitWindowsEx
+
+ERASER_EXPORT
+eraserSetFinishAction(E_IN ERASER_HANDLE param1, E_IN DWORD action);
+// clears the context data array
+ERASER_EXPORT
+eraserClearItems(E_IN ERASER_HANDLE);
+
+
+// Notification
+//
+
+// sets the window to notify
+ERASER_EXPORT
+eraserSetWindow(E_IN ERASER_HANDLE, E_IN HWND);
+// returns the window
+ERASER_EXPORT
+eraserGetWindow(E_IN ERASER_HANDLE, E_OUT HWND*);
+// sets the window message
+ERASER_EXPORT
+eraserSetWindowMessage(E_IN ERASER_HANDLE, E_IN E_UINT32);
+// returns the window message
+ERASER_EXPORT
+eraserGetWindowMessage(E_IN ERASER_HANDLE, E_OUT E_PUINT32);
+
+
+// Statistics
+//
+
+// returns the erased area
+ERASER_EXPORT
+eraserStatGetArea(E_IN ERASER_HANDLE, E_OUT E_PUINT64);
+// returns the erased cluster tip area
+ERASER_EXPORT
+eraserStatGetTips(E_IN ERASER_HANDLE, E_OUT E_PUINT64);
+// returns the amount of data written
+ERASER_EXPORT
+eraserStatGetWiped(E_IN ERASER_HANDLE, E_OUT E_PUINT64);
+// returns the time used (ms)
+ERASER_EXPORT
+eraserStatGetTime(E_IN ERASER_HANDLE, E_OUT E_PUINT32);
+
+
+// Display
+//
+
+// returns what the UI should show (see above for flag descriptions)
+ERASER_EXPORT
+eraserDispFlags(E_IN ERASER_HANDLE, E_OUT E_PUINT8);
+
+
+// Progress information
+//
+
+// returns an estimate of how long the operation takes to complete
+ERASER_EXPORT
+eraserProgGetTimeLeft(E_IN ERASER_HANDLE, E_OUT E_PUINT32);
+// returns the completion percent of current item
+ERASER_EXPORT
+eraserProgGetPercent(E_IN ERASER_HANDLE, E_OUT E_PUINT8);
+// returns the completion percent of the operation
+ERASER_EXPORT
+eraserProgGetTotalPercent(E_IN ERASER_HANDLE, E_OUT E_PUINT8);
+// returns the index of the current overwriting pass
+ERASER_EXPORT
+eraserProgGetCurrentPass(E_IN ERASER_HANDLE, E_OUT E_PUINT16);
+// returns the amount of passes
+ERASER_EXPORT
+eraserProgGetPasses(E_IN ERASER_HANDLE, E_OUT E_PUINT16);
+// returns a message UI can to show to the user telling what is going on
+ERASER_EXPORT
+eraserProgGetMessage(E_IN ERASER_HANDLE, E_OUT LPVOID, E_INOUT E_PUINT16);
+// returns the name of the item that is being processed
+ERASER_EXPORT
+eraserProgGetCurrentDataString(E_IN ERASER_HANDLE, E_OUT LPVOID, E_INOUT E_PUINT16);
+
+
+
+// Control
+//
+
+// starts overwriting in a new thread
+ERASER_EXPORT
+eraserStart(E_IN ERASER_HANDLE);
+// starts overwriting
+ERASER_EXPORT
+eraserStartSync(E_IN ERASER_HANDLE);
+// stops running task
+ERASER_EXPORT
+eraserStop(E_IN ERASER_HANDLE);
+// checks whether task is being processed
+ERASER_EXPORT
+eraserIsRunning(E_IN ERASER_HANDLE, E_OUT E_PUINT8);
+
+
+// Result
+//
+
+// checks whether the task was completed successfully
+ERASER_EXPORT
+eraserCompleted(E_IN ERASER_HANDLE, E_OUT E_PUINT8);
+// checks whether the task failed
+ERASER_EXPORT
+eraserFailed(E_IN ERASER_HANDLE, E_OUT E_PUINT8);
+// checks whether the task was terminated
+ERASER_EXPORT
+eraserTerminated(E_IN ERASER_HANDLE, E_OUT E_PUINT8);
+// returns the amount of error messages in the context array
+ERASER_EXPORT
+eraserErrorStringCount(E_IN ERASER_HANDLE, E_OUT E_PUINT16);
+// retrieves the given error message from the array
+ERASER_EXPORT
+eraserErrorString(E_IN ERASER_HANDLE, E_IN E_UINT16, E_OUT LPVOID, E_INOUT E_PUINT16);
+// returns the amount of failed items in the context array
+ERASER_EXPORT
+eraserFailedCount(E_IN ERASER_HANDLE, E_OUT E_PUINT32);
+// retrieves the given failed item from the array
+ERASER_EXPORT
+eraserFailedString(E_IN ERASER_HANDLE, E_IN E_UINT32, E_OUT LPVOID, E_INOUT E_PUINT16);
+
+
+// Display report
+//
+
+// displays erasing report
+ERASER_EXPORT
+eraserShowReport(E_IN ERASER_HANDLE, E_IN HWND);
+
+
+// Display library options
+//
+
+// displays the options window
+ERASER_EXPORT
+eraserShowOptions(E_IN HWND, E_IN ERASER_OPTIONS_PAGE);
+
+
+// File / directory deletion
+//
+
+// removes a file
+ERASER_EXPORT
+eraserRemoveFile(E_IN LPVOID, E_IN E_UINT16);
+// removes a folder
+ERASER_EXPORT
+eraserRemoveFolder(E_IN LPVOID, E_IN E_UINT16, E_IN E_UINT8);
+
+
+// Helpers
+//
+
+// returns the amount of free disk space on a drive
+ERASER_EXPORT
+eraserGetFreeDiskSpace(E_IN LPVOID, E_IN E_UINT16, E_OUT E_PUINT64);
+
+// returns the cluster size of a partition
+ERASER_EXPORT
+eraserGetClusterSize(E_IN LPVOID, E_IN E_UINT16, E_OUT E_PUINT32);
+
+
+// Test mode
+//
+
+// enables test mode --> files will be opened with sharing enabled
+// and erasing process will be paused after each overwriting pass
+// until eraserTestContinueProcess(...) is called for the handle
+ERASER_EXPORT
+eraserTestEnable(E_IN ERASER_HANDLE);
+
+// continues paused erasing process in test mode
+ERASER_EXPORT
+eraserTestContinueProcess(E_IN ERASER_HANDLE);
+
+
+#if defined(__cplusplus)
+}
+#endif
+
+
+// Helper definitions
+//
+#ifdef DEBUG
+    #define NODEFAULT ASSERT(0)
+#else
+    #define NODEFAULT __assume(0)
+#endif
+
+// "." or ".."
+#define ISNT_SUBFOLDER(lpsz) \
+    ((lpsz)[0] == _T('.') && \
+     ((lpsz)[1] == _T('\0') || \
+      ((lpsz)[1] == _T('.') && \
+       (lpsz)[2] == _T('\0'))))
+#define IS_SUBFOLDER(lpsz) \
+    (!ISNT_SUBFOLDER(lpsz))
+
+// bit mask operations
+//
+#define bitSet(x, mask) \
+    (((x) & (mask)) != 0)
+#define setBit(x, mask) \
+    (x) |= (mask)
+#define unsetBit(x, mask) \
+    (x) &= ~(mask)
+
+// Library internal header file
+//
+#ifdef _DLL_ERASER
+    #include "EraserDllInternal.h"
+#endif
+
+#endif // ERASERDLL_H
Index: /trunk/EraserDll/OptionsDlg.h
===================================================================
--- /trunk/EraserDll/OptionsDlg.h	(revision 4)
+++ /trunk/EraserDll/OptionsDlg.h	(revision 4)
@@ -0,0 +1,66 @@
+// OptionsDlg.h
+//
+// Eraser. Secure data removal. For Windows.
+// Copyright © 1997-2001  Sami Tolvanen (sami@tolvanen.com).
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#ifndef __OPTIONSDLG_H__
+#define __OPTIONSDLG_H__
+
+#include "OptionPages.h"
+
+/////////////////////////////////////////////////////////////////////////////
+// COptionsDlg
+
+class COptionsDlg : public CPropertySheet
+{
+    DECLARE_DYNAMIC(COptionsDlg)
+
+// Construction
+public:
+    COptionsDlg(CWnd* pWndParent = NULL);
+
+// Attributes
+public:
+    COptionsForFiles m_pgFiles;
+    COptionsForFreeSpace m_pgFreeSpace;
+
+    LibrarySettings m_lsSettings;
+
+// Operations
+public:
+
+// Overrides
+    // ClassWizard generated virtual function overrides
+    //{{AFX_VIRTUAL(COptionsDlg)
+    //}}AFX_VIRTUAL
+
+// Implementation
+public:
+    virtual ~COptionsDlg();
+
+// Generated message map functions
+protected:
+    //{{AFX_MSG(COptionsDlg)
+        // NOTE - the ClassWizard will add and remove member functions here.
+    //}}AFX_MSG
+    DECLARE_MESSAGE_MAP()
+};
+
+/////////////////////////////////////////////////////////////////////////////
+
+#endif  // __OPTIONSDLG_H__
Index: /trunk/EraserDll/EraserExport.h
===================================================================
--- /trunk/EraserDll/EraserExport.h	(revision 4)
+++ /trunk/EraserDll/EraserExport.h	(revision 4)
@@ -0,0 +1,7 @@
+#ifdef _DLL_ERASER
+#define ERASER_EXPORT __declspec(dllexport) LONG __stdcall
+#define ERASER_API __declspec(dllexport)
+#else
+#define ERASER_EXPORT __declspec(dllimport) LONG __stdcall
+#define ERASER_API __declspec(dllimport)
+#endif
Index: /trunk/EraserDll/Common.cpp
===================================================================
--- /trunk/EraserDll/Common.cpp	(revision 4)
+++ /trunk/EraserDll/Common.cpp	(revision 4)
@@ -0,0 +1,26 @@
+// Common.cpp
+//
+// Eraser. Secure data removal. For Windows.
+// Copyright © 1997-2001  Sami Tolvanen (sami@tolvanen.com).
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#include "stdafx.h"
+#include "EraserDll.h"
+#define GLOBAL_VARIABLES_HERE
+#include "Common.h"
+bool IsWindowsNT()
+{return isWindowsNT;}
Index: /trunk/EraserDll/OptionPages.cpp
===================================================================
--- /trunk/EraserDll/OptionPages.cpp	(revision 4)
+++ /trunk/EraserDll/OptionPages.cpp	(revision 4)
@@ -0,0 +1,1019 @@
+// OptionPages.cpp
+//
+// Eraser. Secure data removal. For Windows.
+// Copyright © 1997-2001  Sami Tolvanen (sami@tolvanen.com).
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#include "stdafx.h"
+
+#include "Eraser.h"
+#include "EraserDll.h"
+#include "EraserDllInternal.h"
+#include "Options.h"
+#include "OptionPages.h"
+#include "CustomMethodEdit.h"
+#include "PassEditDlg.h"
+#include "Common.h"
+#include "resource.h"
+#include <afxstat_.h>
+
+#ifdef _DEBUG
+#undef THIS_FILE
+static char BASED_CODE THIS_FILE[] = __FILE__;
+#endif
+
+IMPLEMENT_DYNCREATE(COptionsForFiles, CPropertyPage)
+
+IMPLEMENT_DYNCREATE(COptionsForFreeSpace, CPropertyPage)
+
+class COptionsForFilesData
+{
+public:
+	COptionsForFilesData():m_plsSettings(NULL),
+		m_ppgFreeSpace(NULL),
+		m_nSelectedMethodID(DEFAULT_FILE_METHOD_ID),
+		m_nSelectedMethod(-1)
+	{  
+		m_strSelected = _T("");
+		m_bFileClusterTips = FALSE;
+		m_bFileNames = FALSE;
+		m_bFileAlternateDataStreams = FALSE;
+		m_plsSettings = new LibrarySettings();
+		if (!loadLibrarySettings(m_plsSettings))
+			setLibraryDefaults(m_plsSettings);
+		m_bSettingOwner = TRUE;
+
+
+	}
+	~COptionsForFilesData()
+	{
+		if (TRUE == m_bSettingOwner && NULL != m_plsSettings)
+		{
+			delete m_plsSettings;  
+		}
+	}
+	LibrarySettings *m_plsSettings;
+	BOOL m_bSettingOwner;
+	COptionsForFreeSpace *m_ppgFreeSpace;
+	BYTE m_nSelectedMethodID;
+	int m_nSelectedMethod; 
+	CFlatListCtrl   m_lcMethod;
+	CString m_strSelected;
+	BOOL m_bFileClusterTips;
+	BOOL m_bFileNames;
+	BOOL    m_bFileAlternateDataStreams;
+
+};
+
+LibrarySettings* COptionsForFiles::GetLibSettings()
+{
+	return m_pData->m_plsSettings;
+}
+void COptionsForFiles::SetLibSettings(LibrarySettings* val)
+{
+	if (TRUE == m_pData->m_bSettingOwner && NULL != m_pData->m_plsSettings)
+	{
+		delete m_pData->m_plsSettings;
+		m_pData->m_bSettingOwner = FALSE;
+	}
+	m_pData->m_plsSettings=val;
+}
+COptionsForFreeSpace* COptionsForFiles::GetFreeSpaceOpt()
+{
+	return m_pData->m_ppgFreeSpace;
+}
+void COptionsForFiles::SetFreeSpaceOpt(COptionsForFreeSpace* val)
+{
+    m_pData->m_ppgFreeSpace=val;
+}
+BYTE COptionsForFiles::GetSelectedMethodId()
+{
+	return m_pData->m_nSelectedMethodID;
+}
+void COptionsForFiles::SetSelectedMethodId(BYTE val)
+{
+	m_pData->m_nSelectedMethodID=val;
+}
+int COptionsForFiles::GetSelectedMethod()
+{
+	return m_pData->m_nSelectedMethod;
+}
+void COptionsForFiles::SetSelectedMethod(int val)
+{
+	m_pData->m_nSelectedMethod=val;
+}
+CFlatListCtrl& COptionsForFiles::GetMethodList()
+{
+	return m_pData->m_lcMethod;
+}
+/*void COptionsForFiles::SetMethodList(CFlatListCtrl val)
+{	
+	m_pData->m_lcMethod=val;
+}*/
+CString& COptionsForFiles::GetSelectedStr()
+{
+	return m_pData->m_strSelected;
+}
+void COptionsForFiles::SetSelectedStr(CString val)
+{
+	m_pData->m_strSelected=val;
+}
+BOOL& COptionsForFiles::GetFileClusterTips()
+{
+	return m_pData->m_bFileClusterTips;
+}
+void COptionsForFiles::SetFileClusterTips(BOOL val)
+{
+	m_pData->m_bFileClusterTips=val;
+}
+BOOL& COptionsForFiles::GetFileNames()
+{
+	return m_pData->m_bFileNames;
+}
+void COptionsForFiles::SetFileNames(BOOL val)
+{
+	m_pData->m_bFileNames=val;
+}
+BOOL& COptionsForFiles::GetFileAltDataStreams()
+{
+	return m_pData->m_bFileAlternateDataStreams;
+}
+void COptionsForFiles::SetFileAltDataStreams(BOOL val)
+{
+	m_pData->m_bFileAlternateDataStreams=val;
+}
+
+static const int iColumnCount = 3;
+
+static const LPTSTR szColumnNames[] =
+{
+    "#",
+    "Description",
+    "Passes"
+};
+
+static int iColumnWidths[] =
+{
+    30,
+    -1,
+    60
+};
+
+static inline void FormatSelectedField(CString& strOutput, const CString& strName, const CString& strPasses)
+{
+    strOutput = "Selected: " + strName +
+                " (" + strPasses + ((strPasses == "1") ? " pass)" : " passes)");
+}
+
+static void CreateList(CListCtrl& lcMethod)
+{
+    CRect rClient;
+    lcMethod.GetClientRect(&rClient);
+
+    iColumnWidths[1] = rClient.Width() -
+                       iColumnWidths[0] -
+                       iColumnWidths[2] -
+                       2 * GetSystemMetrics(SM_CXBORDER);
+
+    LVCOLUMN lvc;
+    ZeroMemory(&lvc, sizeof(LVCOLUMN));
+
+    lvc.mask        = LVCF_FMT | LVCF_SUBITEM | LVCF_TEXT | LVCF_WIDTH;
+    lvc.fmt         = LVCFMT_LEFT;
+    lvc.pszText     = szColumnNames[0];
+    lvc.cx          = iColumnWidths[0];
+    lvc.iSubItem    = 0;
+    lcMethod.InsertColumn(0, &lvc);
+
+    lvc.mask        = LVCF_FMT | LVCF_SUBITEM | LVCF_TEXT | LVCF_WIDTH;
+    lvc.fmt         = LVCFMT_LEFT;
+    lvc.pszText     = szColumnNames[1];
+    lvc.cx          = iColumnWidths[1];
+    lvc.iSubItem    = 1;
+    lcMethod.InsertColumn(1, &lvc);
+
+    lvc.mask        = LVCF_FMT | LVCF_SUBITEM | LVCF_TEXT | LVCF_WIDTH;
+    lvc.fmt         = LVCFMT_LEFT;
+    lvc.pszText     = szColumnNames[2];
+    lvc.cx          = iColumnWidths[2];
+    lvc.iSubItem    = 2;
+    lcMethod.InsertColumn(2, &lvc);
+
+    lcMethod.SetExtendedStyle(LVS_EX_HEADERDRAGDROP | LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);
+}
+
+// using the nRandomPasses parameter is just a silly hack, cause I wanted to be able to use
+// the same code with both property pages...
+static void UpdateFreeSpaceMethodList(CListCtrl& lcMethod, LibrarySettings *plsSettings, WORD& nRandomPasses)
+{
+    lcMethod.SetRedraw(FALSE);
+
+    try
+    {
+        lcMethod.DeleteAllItems();
+
+        CString         strTmp;
+        BYTE            i;
+        BYTE            nItem = 1;
+        LV_ITEM         lvi;
+        WORD            nPasses = 0;
+        ZeroMemory(&lvi, sizeof(LV_ITEM));
+
+        // built-in
+        for (i = 0; i < nBuiltinMethods; i++, nItem++)
+        {
+            if (i!=4) //FirstLast2K
+            {
+            nPasses = (GetBMethods()[i].m_nMethodID == RANDOM_METHOD_ID) ?
+                        nRandomPasses : GetBMethods()[i].m_nPasses;
+
+            strTmp.Format("%u", (DWORD)nItem);
+            lvi.mask        = LVIF_TEXT | LVIF_PARAM;
+            lvi.lParam      = (LPARAM)GetBMethods()[i].m_nMethodID;
+            lvi.iItem       = nItem;
+            lvi.iSubItem    = 0;
+            lvi.pszText     = strTmp.GetBuffer(strTmp.GetLength());
+            lvi.iItem       = lcMethod.InsertItem(&lvi);
+            strTmp.ReleaseBuffer();
+
+            lvi.mask        = LVIF_TEXT;
+            lvi.iSubItem    = 1;
+            lvi.pszText     = (LPTSTR)GetBMethods()[i].m_szDescription;
+            lcMethod.SetItem(&lvi);
+
+            strTmp.Format("%u", (DWORD)nPasses);
+            lvi.iSubItem    = 2;
+            lvi.pszText     = strTmp.GetBuffer(strTmp.GetLength());
+            lcMethod.SetItem(&lvi);
+            strTmp.ReleaseBuffer();
+            }
+        }
+
+        // custom
+        for (i = 0; i < plsSettings->m_nCMethods; i++, nItem++)
+        {
+            strTmp.Format("%u", (DWORD)nItem);
+            lvi.mask        = LVIF_TEXT | LVIF_PARAM;
+            lvi.lParam      = (LPARAM)plsSettings->m_lpCMethods[i].m_nMethodID;
+            lvi.iItem       = nItem;
+            lvi.iSubItem    = 0;
+            lvi.pszText     = strTmp.GetBuffer(strTmp.GetLength());
+            lvi.iItem       = lcMethod.InsertItem(&lvi);
+            strTmp.ReleaseBuffer();
+
+            lvi.mask        = LVIF_TEXT;
+            lvi.iSubItem    = 1;
+            lvi.pszText     = (LPTSTR)plsSettings->m_lpCMethods[i].m_szDescription;
+            lcMethod.SetItem(&lvi);
+
+            strTmp.Format("%u", (DWORD)plsSettings->m_lpCMethods[i].m_nPasses);
+            lvi.iSubItem    = 2;
+            lvi.pszText     = strTmp.GetBuffer(strTmp.GetLength());
+            lcMethod.SetItem(&lvi);
+            strTmp.ReleaseBuffer();
+        }
+
+        CRect rList, rHeader;
+        CSize size = lcMethod.ApproximateViewRect();
+
+        lcMethod.GetClientRect(&rList);
+        lcMethod.GetHeaderCtrl()->GetClientRect(&rHeader);
+
+        if (size.cy > (rList.Height() + rHeader.Height()))
+            lcMethod.SetColumnWidth(1, iColumnWidths[1] - GetSystemMetrics(SM_CXVSCROLL));
+        else
+            lcMethod.SetColumnWidth(1, iColumnWidths[1]);
+    }
+    catch (...)
+    {
+        ASSERT(FALSE);
+    }
+
+    lcMethod.SetRedraw(TRUE);
+}
+static void UpdateMethodList(CListCtrl& lcMethod, LibrarySettings *plsSettings, WORD& nRandomPasses)
+{
+    lcMethod.SetRedraw(FALSE);
+
+    try
+    {
+        lcMethod.DeleteAllItems();
+
+        CString         strTmp;
+        BYTE            i;
+        BYTE            nItem = 1;
+        LV_ITEM         lvi;
+        WORD            nPasses = 0;
+        ZeroMemory(&lvi, sizeof(LV_ITEM));
+
+        // built-in
+        for (i = 0; i < nBuiltinMethods; i++, nItem++)
+        {
+			
+            nPasses = (GetBMethods()[i].m_nMethodID == RANDOM_METHOD_ID) ?
+                        nRandomPasses : GetBMethods()[i].m_nPasses;
+
+            strTmp.Format("%u", (DWORD)nItem);
+            lvi.mask        = LVIF_TEXT | LVIF_PARAM;
+            lvi.lParam      = (LPARAM)GetBMethods()[i].m_nMethodID;
+            lvi.iItem       = nItem;
+            lvi.iSubItem    = 0;
+            lvi.pszText     = strTmp.GetBuffer(strTmp.GetLength());
+            lvi.iItem       = lcMethod.InsertItem(&lvi);
+            strTmp.ReleaseBuffer();
+
+            lvi.mask        = LVIF_TEXT;
+            lvi.iSubItem    = 1;
+            lvi.pszText     = (LPTSTR)GetBMethods()[i].m_szDescription;
+            lcMethod.SetItem(&lvi);
+
+            strTmp.Format("%u", (DWORD)nPasses);
+            lvi.iSubItem    = 2;
+            lvi.pszText     = strTmp.GetBuffer(strTmp.GetLength());
+            lcMethod.SetItem(&lvi);
+            strTmp.ReleaseBuffer();
+        }
+
+        // custom
+        for (i = 0; i < plsSettings->m_nCMethods; i++, nItem++)
+        {
+            strTmp.Format("%u", (DWORD)nItem);
+            lvi.mask        = LVIF_TEXT | LVIF_PARAM;
+            lvi.lParam      = (LPARAM)plsSettings->m_lpCMethods[i].m_nMethodID;
+            lvi.iItem       = nItem;
+            lvi.iSubItem    = 0;
+            lvi.pszText     = strTmp.GetBuffer(strTmp.GetLength());
+            lvi.iItem       = lcMethod.InsertItem(&lvi);
+            strTmp.ReleaseBuffer();
+
+            lvi.mask        = LVIF_TEXT;
+            lvi.iSubItem    = 1;
+            lvi.pszText     = (LPTSTR)plsSettings->m_lpCMethods[i].m_szDescription;
+            lcMethod.SetItem(&lvi);
+
+            strTmp.Format("%u", (DWORD)plsSettings->m_lpCMethods[i].m_nPasses);
+            lvi.iSubItem    = 2;
+            lvi.pszText     = strTmp.GetBuffer(strTmp.GetLength());
+            lcMethod.SetItem(&lvi);
+            strTmp.ReleaseBuffer();
+        }
+
+        CRect rList, rHeader;
+        CSize size = lcMethod.ApproximateViewRect();
+
+        lcMethod.GetClientRect(&rList);
+        lcMethod.GetHeaderCtrl()->GetClientRect(&rHeader);
+
+        if (size.cy > (rList.Height() + rHeader.Height()))
+            lcMethod.SetColumnWidth(1, iColumnWidths[1] - GetSystemMetrics(SM_CXVSCROLL));
+        else
+            lcMethod.SetColumnWidth(1, iColumnWidths[1]);
+    }
+    catch (...)
+    {
+        ASSERT(FALSE);
+    }
+
+    lcMethod.SetRedraw(TRUE);
+}
+static int SelectMethod(CListCtrl& lcMethod, BYTE nMethodID, CString& str)
+{
+    try
+    {
+        LVFINDINFO lvfi;
+        ZeroMemory(&lvfi, sizeof(LVFINDINFO));
+
+        lvfi.flags  = LVFI_PARAM;
+        lvfi.lParam = (LPARAM)nMethodID;
+
+        int iItem = lcMethod.FindItem(&lvfi);
+
+        if (iItem != -1)
+        {
+            lcMethod.SetItemState(iItem, LVIS_SELECTED, LVIS_SELECTED);
+            FormatSelectedField(str,
+                                lcMethod.GetItemText(iItem, 1),
+                                lcMethod.GetItemText(iItem, 2));
+            return iItem;
+        }
+    }
+    catch (...)
+    {
+        ASSERT(FALSE);
+    }
+
+    return -1;
+}
+
+static BOOL DeleteMethod(LibrarySettings *plsSettings, BYTE nSelectedMethodID)
+{
+    if (AfxMessageBox(IDS_METHOD_DELETE, MB_ICONQUESTION | MB_YESNO, 0) == IDYES)
+    {
+        try
+        {
+            LPMETHOD lpcmNew = 0;
+
+            if (plsSettings->m_nCMethods > 1)
+            {
+                lpcmNew = new METHOD[plsSettings->m_nCMethods - 1];
+
+                for (BYTE i = 0, j = 0; i < plsSettings->m_nCMethods; i++)
+                {
+                    if (plsSettings->m_lpCMethods[i].m_nMethodID != nSelectedMethodID)
+                        lpcmNew[j++] = plsSettings->m_lpCMethods[i];
+                }
+            }
+
+            plsSettings->m_nCMethods--;
+
+            delete[] plsSettings->m_lpCMethods;
+            plsSettings->m_lpCMethods = lpcmNew;
+
+            return TRUE;
+        }
+        catch (CException *e)
+        {
+            e->ReportError(MB_ICONERROR);
+            e->Delete();
+        }
+    }
+
+    return FALSE;
+}
+
+// using the nRandomPasses parameter is just a silly hack, cause I wanted to be able to use
+// the same code with both property pages...
+static BOOL EditMethod(LibrarySettings *plsSettings, BYTE nSelectedMethodID, WORD& nRandomPasses)
+{
+    if (!bitSet(nSelectedMethodID, BUILTIN_METHOD_ID))
+    {
+        try
+        {
+            LPMETHOD lpcm = 0;
+
+            // find the selected method
+            for (BYTE i = 0; i < plsSettings->m_nCMethods; i++)
+            {
+                if (plsSettings->m_lpCMethods[i].m_nMethodID == nSelectedMethodID)
+                {
+                    lpcm = &plsSettings->m_lpCMethods[i];
+                    break;
+                }
+            }
+
+            if (lpcm == 0)
+                return FALSE;
+
+            CCustomMethodEdit cme;
+            cme.LoadCustomMethod(lpcm);
+
+            if (cme.DoModal() == IDOK)
+            {
+                cme.FillCustomMethod(lpcm);
+                return TRUE;
+            }
+        }
+        catch (CException *e)
+        {
+            e->ReportError(MB_ICONERROR);
+            e->Delete();
+        }
+    }
+    else if (nSelectedMethodID == RANDOM_METHOD_ID)
+    {
+        // edit the number of passes
+        CPassEditDlg ped;
+        ped.m_uPasses = nRandomPasses;
+
+        if (ped.DoModal() == IDOK)
+        {
+            nRandomPasses = (WORD)ped.m_uPasses;
+            return TRUE;
+        }
+    }
+
+    return FALSE;
+}
+
+static BOOL NewMethod(LibrarySettings *plsSettings)
+{
+    try
+    {
+        METHOD cmNew;
+        ZeroMemory(&cmNew, sizeof(METHOD));
+
+        CCustomMethodEdit cme;
+        cme.LoadCustomMethod(&cmNew);
+
+        if (cme.DoModal() == IDOK)
+        {
+            BYTE i;
+            cme.FillCustomMethod(&cmNew);
+
+            // assign a method ID
+            cmNew.m_nMethodID = (1 | CUSTOM_METHOD_ID);
+
+            for (i = 0; i < plsSettings->m_nCMethods; i++)
+            {
+                if (plsSettings->m_lpCMethods[i].m_nMethodID == cmNew.m_nMethodID)
+                {
+                    i = 0;
+                    cmNew.m_nMethodID++;
+                }
+            }
+
+            LPMETHOD lpcm = new METHOD[plsSettings->m_nCMethods + 1];
+
+            for (i = 0; i < plsSettings->m_nCMethods; i++)
+                lpcm[i] = plsSettings->m_lpCMethods[i];
+
+            lpcm[plsSettings->m_nCMethods] = cmNew;
+            plsSettings->m_nCMethods++;
+
+            if (plsSettings->m_lpCMethods)
+                delete[] plsSettings->m_lpCMethods;
+
+            plsSettings->m_lpCMethods = lpcm;
+
+            return TRUE;
+        }
+    }
+    catch (CException *e)
+    {
+        e->ReportError(MB_ICONERROR);
+        e->Delete();
+    }
+
+    return FALSE;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// COptionsForFiles property page
+
+COptionsForFiles::COptionsForFiles() : CPropertyPage(IDD_PAGE_FILES),  m_pData(0)
+{    
+	m_pData = new COptionsForFilesData();
+    m_psp.dwFlags &= (~PSP_HASHELP);
+}
+COptionsForFiles* 
+COptionsForFiles::create()
+{
+	AFX_MANAGE_STATE(AfxGetStaticModuleState());
+	return new COptionsForFiles();
+}
+BOOL 
+COptionsForFiles::OnSetActive()
+{
+	
+	
+	return CPropertyPage::OnSetActive();
+}
+COptionsForFiles::~COptionsForFiles()
+{
+	try
+	{
+		delete m_pData;
+	}
+	catch (...) {
+	}
+}
+
+void COptionsForFiles::DoDataExchange(CDataExchange* pDX)
+{
+    CPropertyPage::DoDataExchange(pDX);
+    //{{AFX_DATA_MAP(COptionsForFiles)
+    
+	DDX_Control(pDX, IDC_LIST_METHOD,GetMethodList());
+    DDX_Text(pDX, IDC_STATIC_SELECTED, GetSelectedStr());
+	DDX_Check(pDX, IDC_CHECK_FILECLUSTERTIPS, GetFileClusterTips());
+	DDX_Check(pDX, IDC_CHECK_FILENAMES, GetFileNames());
+    DDX_Check(pDX, IDC_CHECK_ALTERNATESTREAMS, GetFileAltDataStreams());
+	
+	//}}AFX_DATA_MAP 
+}
+
+
+BEGIN_MESSAGE_MAP(COptionsForFiles, CPropertyPage)
+    //{{AFX_MSG_MAP(COptionsForFiles)
+    ON_BN_CLICKED(IDC_BUTTON_DELETE, OnButtonDelete)
+    ON_BN_CLICKED(IDC_BUTTON_EDIT, OnButtonEdit)
+    ON_BN_CLICKED(IDC_BUTTON_NEW, OnButtonNew)
+    ON_NOTIFY(LVN_ITEMCHANGED, IDC_LIST_METHOD, OnItemchangedListMethod)
+	ON_NOTIFY(NM_DBLCLK, IDC_LIST_METHOD, OnDblclkListMethod)
+	//}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+
+/////////////////////////////////////////////////////////////////////////////
+// COptionsForFreeSpace property page
+
+COptionsForFreeSpace::COptionsForFreeSpace() :
+CPropertyPage(IDD_PAGE_FREESPACE /*COptionsForFreeSpace::IDD*/),
+m_plsSettings(0),
+m_ppgFiles(0),
+m_nSelectedMethodID(DEFAULT_UDS_METHOD_ID),
+m_nSelectedMethod(-1)
+{
+    //{{AFX_DATA_INIT(COptionsForFreeSpace)
+    m_bClusterTips = FALSE;
+    m_bDirectoryEntries = FALSE;
+    m_bFreeSpace = FALSE;
+    m_strSelected = _T("");
+    //}}AFX_DATA_INIT
+
+    m_psp.dwFlags &= (~PSP_HASHELP);
+}
+
+COptionsForFreeSpace::~COptionsForFreeSpace()
+{
+}
+
+void COptionsForFreeSpace::DoDataExchange(CDataExchange* pDX)
+{
+    CPropertyPage::DoDataExchange(pDX);
+    //{{AFX_DATA_MAP(COptionsForFreeSpace)
+    DDX_Control(pDX, IDC_LIST_METHOD, m_lcMethod);
+    DDX_Check(pDX, IDC_CHECK_CLUSTERTIPS, m_bClusterTips);
+    DDX_Check(pDX, IDC_CHECK_DIRECTORYENTRIES, m_bDirectoryEntries);
+    DDX_Check(pDX, IDC_CHECK_FREESPACE, m_bFreeSpace);
+    DDX_Text(pDX, IDC_STATIC_SELECTED, m_strSelected);
+    //}}AFX_DATA_MAP
+}
+
+
+BEGIN_MESSAGE_MAP(COptionsForFreeSpace, CPropertyPage)
+    //{{AFX_MSG_MAP(COptionsForFreeSpace)
+    ON_BN_CLICKED(IDC_BUTTON_EDIT, OnButtonEdit)
+    ON_BN_CLICKED(IDC_BUTTON_NEW, OnButtonNew)
+    ON_BN_CLICKED(IDC_BUTTON_DELETE, OnButtonDelete)
+    ON_NOTIFY(LVN_ITEMCHANGED, IDC_LIST_METHOD, OnItemchangedListMethod)
+	ON_NOTIFY(NM_DBLCLK, IDC_LIST_METHOD, OnDblclkListMethod)
+	//}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+
+BOOL COptionsForFiles::OnInitDialog()
+{
+    try
+    {
+		
+        CPropertyPage::OnInitDialog();
+
+         //m_nSelectedMethodID = m_plsSettings->m_nFileMethodID;
+		SetSelectedMethodId(GetLibSettings()->m_nFileMethodID);
+
+        // setup list
+		 //CreateList(m_lcMethod);
+		CreateList(GetMethodList());
+        
+        // add methods to the list
+        UpdateList();
+        // select the correct method
+         //m_nSelectedMethod = SelectMethod(m_lcMethod, m_nSelectedMethodID, m_strSelected);
+		SetSelectedMethod(SelectMethod(GetMethodList(), GetSelectedMethodId(), GetSelectedStr()));
+         //m_bFileClusterTips = bitSet(m_plsSettings->m_uItems, fileClusterTips);
+		SetFileClusterTips(bitSet(GetLibSettings()->m_uItems, fileClusterTips));
+
+        if (!IsWindowsNT())
+        {
+            // file names can be deselected, alternate data streams aren't supported
+             //m_bFileNames = bitSet(m_plsSettings->m_uItems, fileNames);
+			SetFileNames(bitSet(GetLibSettings()->m_uItems, fileNames));
+
+             //m_bFileAlternateDataStreams = FALSE;
+			SetFileAltDataStreams(FALSE);
+            GetDlgItem(IDC_CHECK_ALTERNATESTREAMS)->ShowWindow(SW_HIDE);
+        }
+        else
+        {
+            // alternate data streams are supported, file names will always be cleared
+             //m_bFileAlternateDataStreams = bitSet(m_plsSettings->m_uItems, fileAlternateStreams);
+			SetFileAltDataStreams(bitSet(GetLibSettings()->m_uItems, fileAlternateStreams));
+
+             //m_bFileNames = TRUE;
+			SetFileNames(TRUE);
+            GetDlgItem(IDC_CHECK_FILENAMES)->EnableWindow(FALSE);
+        }
+
+         //EnableButtons(m_nSelectedMethodID);
+		EnableButtons(GetSelectedMethodId());
+
+        UpdateData(FALSE);
+    }
+    catch (...)
+    {
+        ASSERT(FALSE);
+    }
+
+    return TRUE;  // return TRUE unless you set the focus to a control
+                  // EXCEPTION: OCX Property Pages should return FALSE
+}
+
+void COptionsForFiles::OnButtonDelete()
+{
+	/*if (DeleteMethod(m_plsSettings, m_nSelectedMethodID))
+	{
+	UpdateList();
+	m_ppgFreeSpace->UpdateList();
+	}*/
+	if (DeleteMethod(GetLibSettings(), GetSelectedMethodId()))
+    {
+        UpdateList();
+        GetFreeSpaceOpt()->UpdateList();
+    }
+}
+
+void COptionsForFiles::OnButtonEdit()
+{
+
+	if (EditMethod(GetLibSettings(),GetSelectedMethodId(), GetLibSettings()->m_nFileRandom))
+    {
+        UpdateList();
+        SelectMethod(GetMethodList(), GetSelectedMethodId(), GetSelectedStr());
+
+        if (IsWindow(GetFreeSpaceOpt()->GetSafeHwnd()))
+        {
+            GetFreeSpaceOpt()->UpdateList();
+            SelectMethod(GetFreeSpaceOpt()->m_lcMethod, GetFreeSpaceOpt()->m_nSelectedMethodID,
+                         GetFreeSpaceOpt()->m_strSelected);
+            GetFreeSpaceOpt()->UpdateData();
+        }
+    }
+}
+
+void COptionsForFiles::OnButtonNew()
+{
+	/*if (NewMethod(m_plsSettings))
+	{
+	UpdateList();
+	m_ppgFreeSpace->UpdateList();
+	}*/
+	if (NewMethod(GetLibSettings()))
+    {
+        UpdateList();
+        GetFreeSpaceOpt()->UpdateList();
+    }
+}
+
+void COptionsForFiles::OnOK()
+{
+    try
+    {
+        UpdateData(TRUE);
+        GetLibSettings()->m_nFileMethodID = GetSelectedMethodId();
+        unsetBit(GetLibSettings()->m_uItems, fileClusterTips | fileNames | fileAlternateStreams);
+
+        if (GetFileClusterTips())
+            setBit(GetLibSettings()->m_uItems, fileClusterTips);
+        if (GetFileNames())
+            setBit(GetLibSettings()->m_uItems, fileNames);
+        if (GetFileAltDataStreams())
+            setBit(GetLibSettings()->m_uItems, fileAlternateStreams);
+    }
+    catch (...)
+    {
+        ASSERT(FALSE);
+    }
+
+    CPropertyPage::OnOK();
+
+}
+
+void COptionsForFiles::UpdateList()
+{
+    if (IsWindow(GetSafeHwnd()))
+    {
+        UpdateMethodList(GetMethodList(), GetLibSettings(), GetLibSettings()->m_nFileRandom);
+
+        if (GetSelectedMethod() >= GetMethodList().GetItemCount())
+            GetMethodList().SetItemState(0, LVIS_SELECTED, LVIS_SELECTED);
+    }
+}
+
+void COptionsForFiles::OnItemchangedListMethod(NMHDR* pNMHDR, LRESULT* pResult)
+{
+    try
+    {
+        NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
+
+        if (pNMListView->uNewState != pNMListView->uOldState &&
+            pNMListView->uNewState & LVIS_SELECTED)
+        {
+            LVITEM  lvi;
+
+            ZeroMemory(&lvi, sizeof(LVITEM));
+            lvi.mask  = LVIF_PARAM;
+            lvi.iItem = pNMListView->iItem;
+
+            if (GetMethodList().GetItem(&lvi))
+            {
+                SetSelectedMethodId((BYTE)lvi.lParam);
+                SetSelectedMethod(lvi.iItem);
+            }
+
+            // enable / disable buttons
+            EnableButtons(GetSelectedMethodId());
+
+            // selected
+            FormatSelectedField(GetSelectedStr(),
+                                GetMethodList().GetItemText(pNMListView->iItem, 1),
+                                GetMethodList().GetItemText(pNMListView->iItem, 2));
+            UpdateData(FALSE);
+        }
+    }
+    catch (...)
+    {
+        ASSERT(FALSE);
+    }
+
+    *pResult = 0;
+}
+
+void COptionsForFiles::EnableButtons(BYTE nMethodID)
+{
+    GetDlgItem(IDC_BUTTON_EDIT)->EnableWindow(!bitSet(nMethodID, BUILTIN_METHOD_ID) ||
+                                              nMethodID == RANDOM_METHOD_ID);
+    GetDlgItem(IDC_BUTTON_DELETE)->EnableWindow(!bitSet(nMethodID, BUILTIN_METHOD_ID));
+}
+
+void COptionsForFiles::OnDblclkListMethod(NMHDR* /*pNMHDR*/, LRESULT* pResult)
+{
+	OnButtonEdit();
+	*pResult = 0;
+}
+
+
+BOOL COptionsForFreeSpace::OnInitDialog()
+{
+    try
+    {
+        CPropertyPage::OnInitDialog();
+
+        m_nSelectedMethodID = m_plsSettings->m_nUDSMethodID;
+
+        // setup list
+        CreateList(m_lcMethod);
+        // add methods to the list
+        UpdateList();
+        // select the correct method
+        SelectMethod(m_lcMethod, m_nSelectedMethodID, m_strSelected);
+
+        m_bFreeSpace        = bitSet(m_plsSettings->m_uItems, diskFreeSpace);
+        m_bClusterTips      = bitSet(m_plsSettings->m_uItems, diskClusterTips);
+        m_bDirectoryEntries = bitSet(m_plsSettings->m_uItems, diskDirEntries);
+
+        EnableButtons(m_nSelectedMethodID);
+
+        if (IsWindowsNT())
+        {
+            CString strTmp;
+            GetDlgItem(IDC_CHECK_FREESPACE)->GetWindowText(strTmp);
+            strTmp += " (and Master File Table Records)";
+            GetDlgItem(IDC_CHECK_FREESPACE)->SetWindowText(strTmp);
+        }
+
+        UpdateData(FALSE);
+    }
+    catch (...)
+    {
+        ASSERT(FALSE);
+    }
+
+    return TRUE;  // return TRUE unless you set the focus to a control
+                  // EXCEPTION: OCX Property Pages should return FALSE
+}
+
+void COptionsForFreeSpace::OnButtonEdit()
+{
+    if (EditMethod(m_plsSettings, m_nSelectedMethodID, m_plsSettings->m_nUDSRandom))
+    {
+        UpdateList();
+        SelectMethod(m_lcMethod, m_nSelectedMethodID, m_strSelected);
+
+        if (IsWindow(m_ppgFiles->GetSafeHwnd()))
+        {
+            m_ppgFiles->UpdateList();
+            SelectMethod(m_ppgFiles->GetMethodList(), m_ppgFiles->GetSelectedMethodId(), m_ppgFiles->GetSelectedStr());
+            m_ppgFiles->UpdateData();
+        }
+    }
+}
+
+void COptionsForFreeSpace::OnButtonNew()
+{
+    if (NewMethod(m_plsSettings))
+    {
+        UpdateList();
+        m_ppgFiles->UpdateList();
+    }
+}
+
+void COptionsForFreeSpace::OnButtonDelete()
+{
+    if (DeleteMethod(m_plsSettings, m_nSelectedMethodID))
+    {
+        UpdateList();
+        m_ppgFiles->UpdateList();
+    }
+}
+
+void COptionsForFreeSpace::OnOK()
+{
+    try
+    {
+        UpdateData(TRUE);
+
+        m_plsSettings->m_nUDSMethodID       = m_nSelectedMethodID;
+        unsetBit(m_plsSettings->m_uItems, diskFreeSpace | diskClusterTips | diskDirEntries);
+
+        if (m_bFreeSpace)
+            setBit(m_plsSettings->m_uItems, diskFreeSpace);
+        if (m_bClusterTips)
+            setBit(m_plsSettings->m_uItems, diskClusterTips);
+        if (m_bDirectoryEntries)
+            setBit(m_plsSettings->m_uItems, diskDirEntries);
+    }
+    catch (...)
+    {
+        ASSERT(FALSE);
+    }
+
+    CPropertyPage::OnOK();
+}
+
+void COptionsForFreeSpace::UpdateList()
+{
+    if (IsWindow(GetSafeHwnd()))
+    {
+        UpdateFreeSpaceMethodList(m_lcMethod, m_plsSettings, m_plsSettings->m_nUDSRandom);
+
+        if (m_nSelectedMethod >= m_lcMethod.GetItemCount())
+            m_lcMethod.SetItemState(0, LVIS_SELECTED, LVIS_SELECTED);
+    }
+}
+
+void COptionsForFreeSpace::EnableButtons(BYTE nMethodID)
+{
+    GetDlgItem(IDC_BUTTON_EDIT)->EnableWindow(!bitSet(nMethodID, BUILTIN_METHOD_ID) ||
+                                              nMethodID == RANDOM_METHOD_ID);
+    GetDlgItem(IDC_BUTTON_DELETE)->EnableWindow(!bitSet(nMethodID, BUILTIN_METHOD_ID));
+}
+
+void COptionsForFreeSpace::OnItemchangedListMethod(NMHDR* pNMHDR, LRESULT* pResult)
+{
+    try
+    {
+        NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
+
+        if (pNMListView->uNewState != pNMListView->uOldState &&
+            pNMListView->uNewState & LVIS_SELECTED)
+        {
+            LVITEM  lvi;
+
+            ZeroMemory(&lvi, sizeof(LVITEM));
+            lvi.mask  = LVIF_PARAM;
+            lvi.iItem = pNMListView->iItem;
+
+            if (m_lcMethod.GetItem(&lvi))
+            {
+                m_nSelectedMethodID = (BYTE)lvi.lParam;
+                m_nSelectedMethod = lvi.iItem;
+            }
+
+            // enable / disable buttons
+            EnableButtons(m_nSelectedMethodID);
+
+            // selected
+            FormatSelectedField(m_strSelected,
+                                m_lcMethod.GetItemText(pNMListView->iItem, 1),
+                                m_lcMethod.GetItemText(pNMListView->iItem, 2));
+            UpdateData(FALSE);
+        }
+    }
+    catch (...)
+    {
+        ASSERT(FALSE);
+    }
+
+    *pResult = 0;
+}
+
+void COptionsForFreeSpace::OnDblclkListMethod(NMHDR* /*pNMHDR*/, LRESULT* pResult)
+{
+	OnButtonEdit();
+	*pResult = 0;
+}
Index: /trunk/EraserDll/RND.h
===================================================================
--- /trunk/EraserDll/RND.h	(revision 4)
+++ /trunk/EraserDll/RND.h	(revision 4)
@@ -0,0 +1,27 @@
+// RND.h
+//
+// Eraser. Secure data removal. For Windows.
+// Copyright © 1997-2001  Sami Tolvanen (sami@tolvanen.com).
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#ifndef RND_H
+#define RND_H
+
+bool
+wipeFileWithPseudoRandom(CEraserContext *context);
+
+#endif // RND_H
Index: /trunk/EraserDll/Options.cpp
===================================================================
--- /trunk/EraserDll/Options.cpp	(revision 4)
+++ /trunk/EraserDll/Options.cpp	(revision 4)
@@ -0,0 +1,201 @@
+// Options.cpp
+//
+// Eraser. Secure data removal. For Windows.
+// Copyright © 1997-2001  Sami Tolvanen (sami@tolvanen.com).
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#include "stdafx.h"
+#include "EraserDll.h"
+#include "Common.h"
+#include "Options.h"
+#include "..\shared\key.h"
+
+#define LIBRARYSETTINGS_SIZE     (sizeof(LibrarySettings) - sizeof(LPMETHOD))
+#define CMETHOD_SIZE             (sizeof(METHOD) - sizeof(LPPASS))
+#define MAX_CMETHOD_SIZE         (CMETHOD_SIZE + PASSES_MAX * sizeof(PASS))
+#define MAX_LIBRARYSETTINGS_SIZE (LIBRARYSETTINGS_SIZE + (MAX_CUSTOM_METHODS * MAX_CMETHOD_SIZE))
+
+void
+setLibraryDefaults(LibrarySettings *pls)
+{
+    try {
+        ZeroMemory(pls, sizeof(LibrarySettings));
+
+        pls->m_nFileMethodID     = DEFAULT_FILE_METHOD_ID;
+        pls->m_nUDSMethodID      = DEFAULT_UDS_METHOD_ID;
+        pls->m_uItems            = (E_UINT8)-1; // select all
+        pls->m_nFileRandom       = PASSES_RND;
+        pls->m_nUDSRandom        = PASSES_RND;
+        pls->m_nCMethods         = 0;
+        pls->m_lpCMethods        = 0;
+    } catch (...) {
+        ASSERT(0);
+    }
+}
+
+extern bool no_registry;
+
+bool
+loadLibrarySettings(LibrarySettings *pls)
+{
+    try {
+		CKey kReg_reg;
+		CIniKey kReg_ini;
+		CKey &kReg = no_registry ? kReg_ini : kReg_reg;
+        bool    bResult = FALSE;
+        E_UINT32  uSize;
+        E_PUINT8  lpData;
+
+        setLibraryDefaults(pls);
+
+        if (!kReg.Open(HKEY_CURRENT_USER, ERASER_REGISTRY_BASE)) {
+            return false;
+        }
+
+        uSize = kReg.GetValueSize(ERASER_REGISTRY_LIBRARY);
+
+        if (uSize >= LIBRARYSETTINGS_SIZE && uSize <= MAX_LIBRARYSETTINGS_SIZE) {
+            lpData = new E_UINT8[uSize];
+            ZeroMemory(lpData, uSize);
+
+            if (kReg.GetValue((LPVOID)lpData, ERASER_REGISTRY_LIBRARY)) {
+                // basic fields
+                MoveMemory((LPVOID)pls, (LPCVOID)lpData, LIBRARYSETTINGS_SIZE);
+
+                // custom methods
+                if (pls->m_nCMethods > 0 && pls->m_nCMethods <= MAX_CUSTOM_METHODS) {
+                    pls->m_lpCMethods = new METHOD[pls->m_nCMethods];
+
+                    E_UINT32 uPos = LIBRARYSETTINGS_SIZE;
+
+                    for (E_UINT8 i = 0; i < pls->m_nCMethods; i++) {
+                        // custom method fields
+                        MoveMemory((LPVOID)(&pls->m_lpCMethods[i]),
+                                   (LPCVOID)(&lpData[uPos]),
+                                   CMETHOD_SIZE);
+
+                        uPos += CMETHOD_SIZE;
+
+                        // actual pass information
+                        if (pls->m_lpCMethods[i].m_nPasses > 0 &&
+                            pls->m_lpCMethods[i].m_nPasses <= PASSES_MAX) {
+                            pls->m_lpCMethods[i].m_lpPasses = new PASS[pls->m_lpCMethods[i].m_nPasses];
+                            ZeroMemory(pls->m_lpCMethods[i].m_lpPasses,
+                                       pls->m_lpCMethods[i].m_nPasses * sizeof(PASS));
+
+                            MoveMemory((LPVOID)(pls->m_lpCMethods[i].m_lpPasses),
+                                       (LPCVOID)(&lpData[uPos]),
+                                       pls->m_lpCMethods[i].m_nPasses * sizeof(PASS));
+
+                            uPos += (pls->m_lpCMethods[i].m_nPasses * sizeof(PASS));
+                        }
+                    }
+                }
+
+                bResult = true;
+            }
+
+            delete[] lpData;
+            lpData = 0;
+        }
+
+        return bResult;
+    } catch (CException *e) {
+        ASSERT(0);
+        e->ReportError(MB_ICONERROR);
+        e->Delete();
+
+        try {
+			CKey kReg_reg;
+			CIniKey kReg_ini;
+			CKey &kReg = no_registry ? kReg_ini : kReg_reg;
+            if (kReg.Open(HKEY_CURRENT_USER, ERASER_REGISTRY_BASE)) {
+                kReg.DeleteValue(ERASER_REGISTRY_LIBRARY);
+            }
+        } catch (...) {
+            ASSERT(0);
+        }
+    }
+
+    return false;
+}
+
+bool
+saveLibrarySettings(LibrarySettings *pls)
+{
+    try {
+		CKey kReg_reg;
+		CIniKey kReg_ini;
+		CKey &kReg = no_registry ? kReg_ini : kReg_reg;
+        bool    bResult = FALSE;
+        E_PUINT8  lpData;
+        E_UINT8   i;
+        E_UINT32  uSize;
+        E_UINT32  uPos;
+
+        if (!kReg.Open(HKEY_CURRENT_USER, ERASER_REGISTRY_BASE)) {
+            return FALSE;
+        }
+
+        // calculate data size
+        uSize = LIBRARYSETTINGS_SIZE + (pls->m_nCMethods * CMETHOD_SIZE);
+
+        for (i = 0; i < pls->m_nCMethods; i++) {
+            uSize += pls->m_lpCMethods[i].m_nPasses * sizeof(PASS);
+        }
+
+        // allocate memory
+        lpData = new E_UINT8[uSize];
+        ZeroMemory(lpData, uSize);
+
+        // basic information
+        MoveMemory((LPVOID)lpData, (LPCVOID)pls, LIBRARYSETTINGS_SIZE);
+        uPos = LIBRARYSETTINGS_SIZE;
+
+        // custom methods
+        for (i = 0; i < pls->m_nCMethods; i++) {
+            MoveMemory((LPVOID)(&lpData[uPos]),
+                       (LPCVOID)(&pls->m_lpCMethods[i]),
+                       CMETHOD_SIZE);
+
+            uPos += CMETHOD_SIZE;
+
+            // actual pass information
+            if (pls->m_lpCMethods[i].m_nPasses > 0 &&
+                pls->m_lpCMethods[i].m_nPasses <= PASSES_MAX) {
+                MoveMemory((LPVOID)(&lpData[uPos]),
+                           (LPCVOID)(pls->m_lpCMethods[i].m_lpPasses),
+                           pls->m_lpCMethods[i].m_nPasses * sizeof(PASS));
+
+                uPos += (pls->m_lpCMethods[i].m_nPasses * sizeof(PASS));
+            }
+        }
+
+        bResult = (kReg.SetValue((LPVOID)lpData, ERASER_REGISTRY_LIBRARY, uSize) != 0);
+
+        delete[] lpData;
+        lpData = 0;
+
+        return bResult;
+    } catch (CException *e) {
+        ASSERT(0);
+        e->ReportError(MB_ICONERROR);
+        e->Delete();
+    }
+
+    return false;
+}
Index: /trunk/EraserDll/ReportDialog.cpp
===================================================================
--- /trunk/EraserDll/ReportDialog.cpp	(revision 4)
+++ /trunk/EraserDll/ReportDialog.cpp	(revision 4)
@@ -0,0 +1,282 @@
+// ReportDialog.cpp
+//
+// Eraser. Secure data removal. For Windows.
+// Copyright © 1997-2001  Sami Tolvanen (sami@tolvanen.com).
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#include "stdafx.h"
+#include "eraser.h"
+#include "ReportDialog.h"
+#include "..\shared\Utils.h"
+//#include "..\shared\FileDialogEx.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CReportDialog dialog
+
+
+CReportDialog::CReportDialog(CWnd* pParent /*=NULL*/) :
+CDialog(CReportDialog::IDD, pParent),
+m_pstraErrorArray(0)
+{
+    //{{AFX_DATA_INIT(CReportDialog)
+    m_strStatistics = _T("");
+    m_strCompletion = _T("");
+    //}}AFX_DATA_INIT
+}
+
+
+void CReportDialog::DoDataExchange(CDataExchange* pDX)
+{
+    CDialog::DoDataExchange(pDX);
+    //{{AFX_DATA_MAP(CReportDialog)
+    DDX_Control(pDX, IDC_LIST_ERRORS, m_listErrors);
+    DDX_Text(pDX, IDC_EDIT_STATISTICS, m_strStatistics);
+    DDX_Text(pDX, IDC_STATIC_COMPLETION, m_strCompletion);
+    //}}AFX_DATA_MAP
+}
+
+
+BEGIN_MESSAGE_MAP(CReportDialog, CDialog)
+    //{{AFX_MSG_MAP(CReportDialog)
+    ON_BN_CLICKED(IDC_BUTTON_SAVEAS, OnSaveAs)
+	//}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CReportDialog message handlers
+
+const LPCTSTR szFileExtension   = "txt";
+const LPCTSTR szFileFilter      = "Text Files (*.txt)|*.txt||";
+const LPCTSTR szSaveTitle       = "Save Report As";
+
+const LPCTSTR szInformation     = "Information:";
+const LPCTSTR szFailures        = "Failures:";
+
+void CReportDialog::OnSaveAs()
+{
+    // Was CfileDialogEx now with MFC7 we can change back to MFC Class
+	CFileDialog fd(FALSE,
+                     "txt",
+                     "*.txt",//NULL,
+                     OFN_EXPLORER | OFN_PATHMUSTEXIST |OFN_ENABLESIZING |OFN_NODEREFERENCELINKS | OFN_FILEMUSTEXIST | OFN_SHOWHELP | OFN_OVERWRITEPROMPT,
+                     szFileFilter,
+                     AfxGetMainWnd());
+    fd.m_ofn.lpstrTitle = szSaveTitle;
+
+    if (fd.DoModal() == IDOK)
+    {
+        CString strFile = fd.GetPathName();
+        CString strTemp;
+        DWORD uIndex, uSize;
+        CStdioFile file;
+
+        if (file.Open((LPCTSTR)strFile, CFile::modeCreate | CFile::modeWrite))
+        {
+            try
+            {
+                // information
+                strTemp.Format("%s\n  ", szInformation);
+                file.WriteString(strTemp);
+                file.WriteString(m_strStatistics);
+
+                // failures
+                if (AfxIsValidAddress(m_pstraErrorArray, sizeof(CStringArray)) &&
+                    m_pstraErrorArray->GetSize() > 0)
+                {
+                    strTemp.Format("\n\n%s\n", szFailures);
+                    file.WriteString(strTemp);
+
+                    uSize = m_pstraErrorArray->GetSize();
+                    for (uIndex = 0; uIndex < uSize; uIndex++)
+                    {
+                        strTemp = "  " + m_pstraErrorArray->GetAt(uIndex) + "\n";
+                        file.WriteString(strTemp);
+                    }
+                }
+            }
+            catch (CException *e)
+            {
+                e->ReportError(MB_ICONERROR);
+                e->Delete();
+            }
+
+            file.Close();
+        }
+    }
+}
+
+BOOL CReportDialog::OnInitDialog()
+{
+    CDialog::OnInitDialog();
+
+    // create list
+    CRect rClient;
+    m_listErrors.GetClientRect(&rClient);
+
+    int iColumnWidths[2];
+
+    iColumnWidths[0] = 30;
+    iColumnWidths[1] = rClient.Width() -
+                       iColumnWidths[0];
+                       // - 2 * GetSystemMetrics(SM_CXBORDER);
+
+    LVCOLUMN lvc;
+    ZeroMemory(&lvc, sizeof(LVCOLUMN));
+
+    lvc.mask        = LVCF_FMT | LVCF_SUBITEM | LVCF_TEXT | LVCF_WIDTH;
+    lvc.fmt         = LVCFMT_LEFT;
+    lvc.pszText     = "#";
+    lvc.cx          = iColumnWidths[0];
+    lvc.iSubItem    = 0;
+    m_listErrors.InsertColumn(0, &lvc);
+
+    lvc.mask        = LVCF_FMT | LVCF_SUBITEM | LVCF_TEXT | LVCF_WIDTH;
+    lvc.fmt         = LVCFMT_LEFT;
+    lvc.pszText     = "Item";
+    lvc.cx          = iColumnWidths[1];
+    lvc.iSubItem    = 1;
+    m_listErrors.InsertColumn(1, &lvc);
+
+    m_listErrors.SetExtendedStyle(LVS_EX_FULLROWSELECT);
+
+    // fill list
+    if (AfxIsValidAddress(m_pstraErrorArray, sizeof(CStringArray)))
+    {
+        int iSize = m_pstraErrorArray->GetSize();
+
+        if (iSize > 0)
+        {
+            m_listErrors.SetRedraw(FALSE);
+
+            try
+            {
+                m_listErrors.DeleteAllItems();
+
+                CString strTemp;
+                int i;
+                int iMaxWidth = iColumnWidths[1];
+                int iStringWidth;
+                LV_ITEM lvi;
+                ZeroMemory(&lvi, sizeof(LV_ITEM));
+
+                for (i = 0; i < iSize; i++)
+                {
+                    strTemp.Format("%i", i + 1);
+                    lvi.mask        = LVIF_TEXT;
+                    lvi.iItem       = i;
+                    lvi.iSubItem    = 0;
+                    lvi.pszText     = strTemp.GetBuffer(strTemp.GetLength());
+                    lvi.iItem       = m_listErrors.InsertItem(&lvi);
+                    strTemp.ReleaseBuffer();
+
+                    strTemp = m_pstraErrorArray->GetAt(i);
+
+                    iStringWidth = m_listErrors.GetStringWidth(strTemp);
+                    if (iStringWidth > iMaxWidth)
+                        iMaxWidth = iStringWidth;
+
+                    lvi.mask        = LVIF_TEXT;
+                    lvi.iSubItem    = 1;
+                    lvi.pszText     = strTemp.GetBuffer(strTemp.GetLength());
+                    m_listErrors.SetItem(&lvi);
+                    strTemp.ReleaseBuffer();
+                }
+
+                if (iMaxWidth > iColumnWidths[1])
+                    m_listErrors.SetColumnWidth(1, iMaxWidth + GetSystemMetrics(SM_CXVSCROLL));
+                else
+                {
+                    CRect rHeader;
+                    CSize size = m_listErrors.ApproximateViewRect();
+                    m_listErrors.GetHeaderCtrl()->GetClientRect(&rHeader);
+
+                    if (size.cy > (rClient.Height() + rHeader.Height()))
+                        m_listErrors.SetColumnWidth(1, iColumnWidths[1] - GetSystemMetrics(SM_CXVSCROLL));
+                }
+            }
+            catch (...)
+            {
+                ASSERT(0);
+            }
+
+            m_listErrors.SetRedraw(TRUE);
+        }
+#ifdef HIDE_FAILURE_LIST_IF_EMPTY
+        else
+        {
+            int iMove;
+            CRect rectItem;
+
+            CWnd *pWnd = GetDlgItem(IDC_EDIT_STATISTICS);
+
+            // calc. distance between the error list and the info edit
+            pWnd->GetWindowRect(&rectItem);
+            ScreenToClient(&rectItem);
+            iMove = rectItem.bottom;
+
+            m_listErrors.GetWindowRect(&rectItem);
+            ScreenToClient(&rectItem);
+            iMove = rectItem.bottom - iMove;
+
+            // hide & move the list
+            m_listErrors.ShowWindow(SW_HIDE);
+            m_listErrors.SetWindowPos(NULL, rectItem.left, rectItem.top - iMove, 0, 0,
+                                      SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
+
+            // hide & move the header
+            pWnd = GetDlgItem(IDC_STATIC_FAILURES_HEADER);
+            pWnd->ShowWindow(SW_HIDE);
+
+            pWnd->GetWindowRect(&rectItem);
+            ScreenToClient(&rectItem);
+
+            pWnd->SetWindowPos(NULL, rectItem.left, rectItem.top - iMove, 0, 0,
+                               SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
+
+            // and the buttons
+            pWnd = GetDlgItem(IDCANCEL);
+            pWnd->GetWindowRect(&rectItem);
+            ScreenToClient(&rectItem);
+
+            pWnd->SetWindowPos(NULL, rectItem.left, rectItem.top - iMove, 0, 0,
+                               SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
+
+            pWnd = GetDlgItem(IDC_BUTTON_SAVEAS);
+            pWnd->GetWindowRect(&rectItem);
+            ScreenToClient(&rectItem);
+
+            pWnd->SetWindowPos(NULL, rectItem.left, rectItem.top - iMove, 0, 0,
+                               SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
+
+            // finally, resize the window
+            GetWindowRect(&rectItem);
+            SetWindowPos(NULL, 0, 0, rectItem.Width(), rectItem.Height() - iMove,
+                         SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
+        }
+#endif
+    }
+
+    return TRUE;  // return TRUE unless you set the focus to a control
+                  // EXCEPTION: OCX Property Pages should return FALSE
+}
+
Index: /trunk/EraserDll/SecManDlg.cpp
===================================================================
--- /trunk/EraserDll/SecManDlg.cpp	(revision 4)
+++ /trunk/EraserDll/SecManDlg.cpp	(revision 4)
@@ -0,0 +1,68 @@
+// SecManDlg.cpp : implementation file
+//
+
+#include "stdafx.h"
+#include "EraserDll.h"
+#include "SecManDlg.h"
+#include ".\secmandlg.h"
+
+
+// CSecManDlg dialog
+
+IMPLEMENT_DYNAMIC(CSecManDlg, CDialog)
+CSecManDlg::CSecManDlg(CWnd* pParent /*=NULL*/)
+	: CDialog(CSecManDlg::IDD, pParent)
+	, m_Password(_T(""))
+	, m_PasswordConfirm(_T(""))
+	, m_mMode(CHECKUP)
+{
+}
+
+CSecManDlg::~CSecManDlg()
+{
+}
+
+void CSecManDlg::DoDataExchange(CDataExchange* pDX)
+{
+	CDialog::DoDataExchange(pDX);
+	DDX_Text(pDX, IDC_EDIT_SECMAN_PASSWD, m_Password);
+	DDX_Text(pDX, IDC_EDIT_SECMAN_PASSWDCONFIRM, m_PasswordConfirm);
+	
+}
+
+
+BEGIN_MESSAGE_MAP(CSecManDlg, CDialog)
+END_MESSAGE_MAP()
+
+
+// CSecManDlg message handlers
+
+void CSecManDlg::OnOK()
+{
+	// TODO: Add your specialized code here and/or call the base class
+	UpdateData();
+	if (SETUP == m_mMode && m_Password != m_PasswordConfirm)
+	{
+		this->MessageBox(CString(MAKEINTRESOURCE(IDS_PASSWDNOTMATCH)), "Error", MB_OK | MB_ICONERROR);
+		Clear();
+		UpdateData(FALSE);
+		GetDlgItem(IDC_EDIT_SECMAN_PASSWD)->SetFocus();		
+		return;
+	}
+	CDialog::OnOK();
+	
+}
+
+BOOL CSecManDlg::OnInitDialog()
+{
+	CDialog::OnInitDialog();
+
+	if (SETUP == m_mMode)
+	{
+		GetDlgItem(IDC_EDIT_SECMAN_PASSWDCONFIRM)->ShowWindow(SW_SHOW);
+		GetDlgItem(IDC_STATIC_CONFIRM)->ShowWindow(SW_SHOW);
+	}
+
+	return TRUE;  // return TRUE unless you set the focus to a control
+	// EXCEPTION: OCX Property Pages should return FALSE
+}
Index: /trunk/EraserDll/EraserDll.vcproj
===================================================================
--- /trunk/EraserDll/EraserDll.vcproj	(revision 4)
+++ /trunk/EraserDll/EraserDll.vcproj	(revision 4)
@@ -0,0 +1,1877 @@
+<?xml version="1.0" encoding="windows-1251"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="EraserDll"
+	ProjectGUID="{31F52DA7-B9F6-452D-823F-E1EFDF283995}"
+	RootNamespace="EraserDll"
+	Keyword="MFCProj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+		<Platform
+			Name="x64"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)\bin\80\$(ConfigurationName)"
+			IntermediateDirectory="$(SolutionDir)\tmp\80\$(ConfigurationName)\$(ProjectName)"
+			ConfigurationType="2"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			UseOfMFC="2"
+			ATLMinimizesCRunTimeLibraryUsage="false"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+				CommandLine="copy %0 command.cmd&#x0D;&#x0A;if not exist $(SolutionDir)\lib md $(SolutionDir)\lib&#x0D;&#x0A;if not exist $(SolutionDir)\lib\$(ConfigurationName) md $(SolutionDir)\lib\$(ConfigurationName)&#x0D;&#x0A;"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+				PreprocessorDefinitions="_DEBUG"
+				MkTypLibCompatible="true"
+				SuppressStartupBanner="true"
+				TargetEnvironment="1"
+				TypeLibraryName=".\Debug/EraserDll.tlb"
+				HeaderFileName=""
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalOptions="/EHa"
+				Optimization="0"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;_DLL_ERASER;_CRT_SECURE_NO_DEPRECATE"
+				ExceptionHandling="0"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="2"
+				PrecompiledHeaderThrough="stdafx.h"
+				PrecompiledHeaderFile="$(IntDir)\EraserDll.pch"
+				AssemblerListingLocation=""
+				ObjectFile="$(IntDir)/"
+				ProgramDataBaseFileName="$(IntDir)/vc70.pdb"
+				WarningLevel="3"
+				SuppressStartupBanner="true"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+				PreprocessorDefinitions="_DEBUG"
+				Culture="1035"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="netapi32.lib"
+				OutputFile="$(OutDir)\Eraser.dll"
+				LinkIncremental="1"
+				SuppressStartupBanner="true"
+				ModuleDefinitionFile=".\Eraser.def"
+				GenerateDebugInformation="true"
+				ProgramDatabaseFile="$(OutDir)\EraserDll.pdb"
+				SubSystem="2"
+				ImportLibrary="$(SolutionDir)\lib\80\$(ConfigurationName)\Eraser.lib"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Debug|x64"
+			OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+			ConfigurationType="2"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			UseOfMFC="2"
+			ATLMinimizesCRunTimeLibraryUsage="false"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+				CommandLine="copy %0 command.cmd&#x0D;&#x0A;if not exist $(SolutionDir)\lib md $(SolutionDir)\lib&#x0D;&#x0A;if not exist $(SolutionDir)\lib\$(ConfigurationName) md $(SolutionDir)\lib\$(ConfigurationName)&#x0D;&#x0A;"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+				PreprocessorDefinitions="_DEBUG"
+				MkTypLibCompatible="true"
+				SuppressStartupBanner="true"
+				TargetEnvironment="3"
+				TypeLibraryName=".\Debug/EraserDll.tlb"
+				HeaderFileName=""
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalOptions="/EHa"
+				Optimization="0"
+				PreprocessorDefinitions="_DEBUG;_WINDOWS;_USRDLL;_DLL_ERASER;_CRT_SECURE_NO_DEPRECATE"
+				ExceptionHandling="0"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="2"
+				PrecompiledHeaderThrough="stdafx.h"
+				PrecompiledHeaderFile="$(IntDir)\EraserDll.pch"
+				AssemblerListingLocation=""
+				ObjectFile="$(IntDir)/"
+				ProgramDataBaseFileName="$(IntDir)/vc70.pdb"
+				WarningLevel="3"
+				SuppressStartupBanner="true"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+				PreprocessorDefinitions="_DEBUG"
+				Culture="1035"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="netapi32.lib"
+				OutputFile="$(OutDir)\Eraser.dll"
+				LinkIncremental="1"
+				SuppressStartupBanner="true"
+				ModuleDefinitionFile=".\Eraser.def"
+				GenerateDebugInformation="true"
+				ProgramDatabaseFile="$(OutDir)\EraserDll.pdb"
+				SubSystem="2"
+				ImportLibrary="$(SolutionDir)\lib\80\$(ConfigurationName)\Eraser.lib"
+				TargetMachine="17"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)\bin\80\$(ConfigurationName)"
+			IntermediateDirectory="$(SolutionDir)\tmp\80\$(ConfigurationName)\$(ProjectName)"
+			ConfigurationType="2"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			UseOfMFC="1"
+			ATLMinimizesCRunTimeLibraryUsage="false"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+				CommandLine="copy %0 command.cmd&#x0D;&#x0A;if not exist $(SolutionDir)\lib md $(SolutionDir)\lib&#x0D;&#x0A;if not exist $(SolutionDir)\lib\$(ConfigurationName) md $(SolutionDir)\lib\$(ConfigurationName)&#x0D;&#x0A;"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+				PreprocessorDefinitions="NDEBUG"
+				MkTypLibCompatible="true"
+				SuppressStartupBanner="true"
+				TargetEnvironment="1"
+				TypeLibraryName=".\Release/EraserDll.tlb"
+				HeaderFileName=""
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalOptions="/GD "
+				Optimization="3"
+				InlineFunctionExpansion="1"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;_DLL_ERASER;_CRT_SECURE_NO_DEPRECATE"
+				RuntimeLibrary="0"
+				UsePrecompiledHeader="2"
+				PrecompiledHeaderThrough="stdafx.h"
+				PrecompiledHeaderFile="$(IntDir)\EraserDll.pch"
+				AssemblerListingLocation=""
+				ObjectFile="$(IntDir)/"
+				ProgramDataBaseFileName="$(IntDir)/vc70.pdb"
+				WarningLevel="4"
+				SuppressStartupBanner="true"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+				PreprocessorDefinitions="NDEBUG"
+				Culture="1033"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="netapi32.lib"
+				OutputFile="$(OutDir)\Eraser.dll"
+				LinkIncremental="1"
+				SuppressStartupBanner="true"
+				ModuleDefinitionFile=".\Eraser.def"
+				ProgramDatabaseFile=""
+				SubSystem="2"
+				ImportLibrary="$(SolutionDir)\lib\80\$(ConfigurationName)\Eraser.lib"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|x64"
+			OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+			ConfigurationType="2"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			UseOfMFC="1"
+			ATLMinimizesCRunTimeLibraryUsage="false"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+				CommandLine="copy %0 command.cmd&#x0D;&#x0A;if not exist $(SolutionDir)\lib md $(SolutionDir)\lib&#x0D;&#x0A;if not exist $(SolutionDir)\lib\$(ConfigurationName) md $(SolutionDir)\lib\$(ConfigurationName)&#x0D;&#x0A;"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+				PreprocessorDefinitions="NDEBUG"
+				MkTypLibCompatible="true"
+				SuppressStartupBanner="true"
+				TargetEnvironment="3"
+				TypeLibraryName=".\Release/EraserDll.tlb"
+				HeaderFileName=""
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalOptions="/GD "
+				Optimization="3"
+				InlineFunctionExpansion="1"
+				PreprocessorDefinitions="NDEBUG;_WINDOWS;_USRDLL;_DLL_ERASER;_CRT_SECURE_NO_DEPRECATE"
+				RuntimeLibrary="0"
+				UsePrecompiledHeader="2"
+				PrecompiledHeaderThrough="stdafx.h"
+				PrecompiledHeaderFile="$(IntDir)\EraserDll.pch"
+				AssemblerListingLocation=""
+				ObjectFile="$(IntDir)/"
+				ProgramDataBaseFileName="$(IntDir)/vc70.pdb"
+				WarningLevel="4"
+				SuppressStartupBanner="true"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+				PreprocessorDefinitions="NDEBUG"
+				Culture="1033"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="netapi32.lib"
+				OutputFile="$(OutDir)\Eraser.dll"
+				LinkIncremental="1"
+				SuppressStartupBanner="true"
+				ModuleDefinitionFile=".\Eraser.def"
+				ProgramDatabaseFile=""
+				SubSystem="2"
+				ImportLibrary="$(SolutionDir)\lib\80\$(ConfigurationName)\Eraser.lib"
+				TargetMachine="17"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+			>
+			<File
+				RelativePath="ByteEdit.cpp"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath="Common.cpp"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath="Custom.cpp"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath="CustomMethodEdit.cpp"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath="DOD.cpp"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath="Eraser.cpp"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath="Eraser.def"
+				>
+			</File>
+			<File
+				RelativePath="Eraser.rc"
+				>
+			</File>
+			<File
+				RelativePath="FAT.cpp"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath="File.cpp"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath="..\shared\FileDialogEx.cpp"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath="..\shared\FileHelper.cpp"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath=".\FileLockResolver.cpp"
+				>
+			</File>
+			<File
+				RelativePath="FillMemoryWith.cpp"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath=".\FirstLast2kb.cpp"
+				>
+			</File>
+			<File
+				RelativePath="..\shared\FlatHeaderCtrl.cpp"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath="..\shared\FlatListCtrl.cpp"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath="FreeSpace.cpp"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath="Gutmann.cpp"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath="..\shared\InPlaceEdit.cpp"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath="..\shared\key.cpp"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath="NTFS.cpp"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath="OptionPages.cpp"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath="Options.cpp"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath="OptionsDlg.cpp"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath="Pass.cpp"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath="PassEditDlg.cpp"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath="Random.cpp"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath="ReportDialog.cpp"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath="RND.cpp"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath="sboxes.cpp"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath=".\Schneier7Pass.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\SecManDlg.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\SecurityManager.cpp"
+				>
+			</File>
+			<File
+				RelativePath="..\shared\SeException.cpp"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath="StdAfx.cpp"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+						UsePrecompiledHeader="1"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+						UsePrecompiledHeader="1"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+						UsePrecompiledHeader="1"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+						UsePrecompiledHeader="1"
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath="tiger.cpp"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath="..\shared\UserInfo.cpp"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="0"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Optimization="3"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl"
+			>
+			<File
+				RelativePath="ByteEdit.h"
+				>
+			</File>
+			<File
+				RelativePath="Common.h"
+				>
+			</File>
+			<File
+				RelativePath="Custom.h"
+				>
+			</File>
+			<File
+				RelativePath="CustomMethodEdit.h"
+				>
+			</File>
+			<File
+				RelativePath="DOD.h"
+				>
+			</File>
+			<File
+				RelativePath="Eraser.h"
+				>
+			</File>
+			<File
+				RelativePath="EraserDll.h"
+				>
+			</File>
+			<File
+				RelativePath="EraserDllInternal.h"
+				>
+			</File>
+			<File
+				RelativePath="FAT.h"
+				>
+			</File>
+			<File
+				RelativePath="File.h"
+				>
+			</File>
+			<File
+				RelativePath="..\shared\FileDialogEx.h"
+				>
+			</File>
+			<File
+				RelativePath="..\shared\FileHelper.h"
+				>
+			</File>
+			<File
+				RelativePath=".\FileLockResolver.h"
+				>
+			</File>
+			<File
+				RelativePath="FillMemoryWith.h"
+				>
+			</File>
+			<File
+				RelativePath=".\FirstLast2kb.h"
+				>
+			</File>
+			<File
+				RelativePath="..\shared\FlatHeaderCtrl.h"
+				>
+			</File>
+			<File
+				RelativePath="..\shared\FlatListCtrl.h"
+				>
+			</File>
+			<File
+				RelativePath="FreeSpace.h"
+				>
+			</File>
+			<File
+				RelativePath="Gutmann.h"
+				>
+			</File>
+			<File
+				RelativePath="..\shared\InPlaceEdit.h"
+				>
+			</File>
+			<File
+				RelativePath=".\isaac.hpp"
+				>
+			</File>
+			<File
+				RelativePath="..\shared\key.h"
+				>
+			</File>
+			<File
+				RelativePath="..\shared\MemDC.h"
+				>
+			</File>
+			<File
+				RelativePath="NTFS.h"
+				>
+			</File>
+			<File
+				RelativePath="OptionPages.h"
+				>
+			</File>
+			<File
+				RelativePath="options.h"
+				>
+			</File>
+			<File
+				RelativePath="OptionsDlg.h"
+				>
+			</File>
+			<File
+				RelativePath="Pass.h"
+				>
+			</File>
+			<File
+				RelativePath="PassEditDlg.h"
+				>
+			</File>
+			<File
+				RelativePath="Random.h"
+				>
+			</File>
+			<File
+				RelativePath="ReportDialog.h"
+				>
+			</File>
+			<File
+				RelativePath="Resource.h"
+				>
+			</File>
+			<File
+				RelativePath="RND.h"
+				>
+			</File>
+			<File
+				RelativePath=".\Schneier7pass.h"
+				>
+			</File>
+			<File
+				RelativePath=".\SecManDlg.h"
+				>
+			</File>
+			<File
+				RelativePath=".\SecurityManager.h"
+				>
+			</File>
+			<File
+				RelativePath="..\shared\SeException.h"
+				>
+			</File>
+			<File
+				RelativePath="Stack.h"
+				>
+			</File>
+			<File
+				RelativePath="StdAfx.h"
+				>
+			</File>
+			<File
+				RelativePath="tiger.h"
+				>
+			</File>
+			<File
+				RelativePath="..\version.h"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Resource Files"
+			Filter="ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe"
+			>
+			<File
+				RelativePath="res\Eraser.ico"
+				>
+			</File>
+			<File
+				RelativePath="res\Eraser.rc2"
+				>
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+		<Global
+			Name="RESOURCE_FILE"
+			Value="Eraser.rc"
+		/>
+	</Globals>
+</VisualStudioProject>
Index: /trunk/EraserDll/StdAfx.h
===================================================================
--- /trunk/EraserDll/StdAfx.h	(revision 4)
+++ /trunk/EraserDll/StdAfx.h	(revision 4)
@@ -0,0 +1,99 @@
+// stdafx.h : include file for standard system include files,
+//  or project specific include files that are used frequently, but
+//      are changed infrequently
+//
+// Eraser. Secure data removal. For Windows.
+// Copyright © 1997-2001  Sami Tolvanen (sami@tolvanen.com).
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#ifdef _UNICODE
+#error UNICODE is not supported!
+#endif
+
+#undef NOCRYPT
+#pragma once
+
+#ifndef VC_EXTRALEAN
+#define VC_EXTRALEAN	// Exclude rarely-used items from Windows headers.
+#endif
+
+// Modify the following defines if you have to target an OS before the ones 
+// specified in the following code. See MSDN for the latest information
+// about corresponding values for different operating systems.
+#ifndef WINVER		// Permit use of features specific to Windows 95 and Windows NT 4.0 or later.
+#define WINVER 0x0400	// Change this to the appropriate value to target 
+#endif                     // Windows 98 and Windows 2000 or later.
+
+#ifndef _WIN32_WINNT	// Permit use of features specific to Windows NT 4.0 or later.
+#define _WIN32_WINNT 0x0400	// Change this to the appropriate value to target 
+#endif		         // Windows 98 and Windows 2000 or later.			
+
+#ifndef _WIN32_WINDOWS	      // Permit use of features specific to Windows 98 or later.
+#define _WIN32_WINDOWS 0x0410    // Change this to the appropriate value to target 
+#endif			      // Windows Millennium Edition or later.
+
+#ifndef _WIN32_IE		// Permit use of features specific to Internet Explorer 4.0 or later.
+#define _WIN32_IE 0x0400   // Change this to the appropriate value to target 
+#endif			// Internet Explorer 5.0 or later.
+
+#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS  // Some CString constructors will be explicit.
+
+// Turns off MFC feature that hides of some common warning messages
+// that are frequently and safely ignored .
+#define _AFX_ALL_WARNINGS
+#include <afxwin.h>         // MFC core and standard components
+#include <afxext.h>         // MFC extensions
+
+#define _AFX_NO_OLE_SUPPORT
+
+#ifndef _AFX_NO_OLE_SUPPORT
+#include <afxole.h>         // MFC OLE classes
+#include <afxodlgs.h>       // MFC OLE dialog classes
+#include <afxdisp.h>        // MFC OLE automation classes
+#endif // _AFX_NO_OLE_SUPPORT
+
+
+#define _AFX_NO_DB_SUPPORT
+
+#ifndef _AFX_NO_DB_SUPPORT
+#include <afxdb.h>          // MFC ODBC database classes
+#endif // _AFX_NO_DB_SUPPORT
+
+#define _AFX_NO_DAO_SUPPORT
+
+#ifndef _AFX_NO_DAO_SUPPORT
+#include <afxdao.h>         // MFC DAO database classes
+#endif // _AFX_NO_DAO_SUPPORT
+
+#ifndef _AFX_NO_AFXCMN_SUPPORT
+#include <afxcmn.h>         // MFC support for Windows 95 Common Controls
+#endif // _AFX_NO_AFXCMN_SUPPORT
+
+#include <afxmt.h>
+#include <afxtempl.h>
+#include <afxcoll.h>
+#include <eh.h>                       // structured exception
+#include "..\shared\SeException.h"    // handling
+#include <Shlwapi.h>
+
+#ifndef _AFXDLL
+#define AfxLoadLibrary  ::LoadLibrary
+#define AfxFreeLibrary  ::FreeLibrary
+#endif
+
+// use intrinsic memory functions
+#pragma intrinsic(memset, memcpy)
Index: /trunk/EraserDll/FreeSpace.h
===================================================================
--- /trunk/EraserDll/FreeSpace.h	(revision 4)
+++ /trunk/EraserDll/FreeSpace.h	(revision 4)
@@ -0,0 +1,43 @@
+// FreeSpace.h
+//
+// Eraser. Secure data removal. For Windows.
+// Copyright © 1997-2001  Sami Tolvanen (sami@tolvanen.com).
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#ifndef FREESPACE_H
+#define FREESPACE_H
+
+void
+countFilesOnDrive(CEraserContext *context, const CString& strDrive, E_UINT32& uFiles, E_UINT32& uFolders);
+bool
+getClusterSize(LPCTSTR szDrive, E_UINT32& uCluster);
+bool
+getClusterAndSectorSize(LPCTSTR szDrive, E_UINT32& uCluster, E_UINT32& uSector);
+
+bool
+getPartitionType(PARTITIONINFO& pi);
+bool
+getPartitionInformation(CEraserContext *context, TCHAR cDrive);
+
+bool
+wipeMFTRecords(CEraserContext *context);
+bool
+wipeClusterTips(CEraserContext *context);
+bool
+wipeFreeSpace(CEraserContext *context);
+
+#endif
Index: /trunk/EraserDll/Sboxes.cpp
===================================================================
--- /trunk/EraserDll/Sboxes.cpp	(revision 4)
+++ /trunk/EraserDll/Sboxes.cpp	(revision 4)
@@ -0,0 +1,522 @@
+// Sboxes.cpp
+//
+// Combined four S-boxes for the tiger hash function
+
+#include "stdafx.h"
+#include "EraserDll.h"
+
+E_UINT64 table[4 * 256] =
+{
+    0x02AAB17CF7E90C5E  /*    0 */,    0xAC424B03E243A8EC  /*    1 */,
+    0x72CD5BE30DD5FCD3  /*    2 */,    0x6D019B93F6F97F3A  /*    3 */,
+    0xCD9978FFD21F9193  /*    4 */,    0x7573A1C9708029E2  /*    5 */,
+    0xB164326B922A83C3  /*    6 */,    0x46883EEE04915870  /*    7 */,
+    0xEAACE3057103ECE6  /*    8 */,    0xC54169B808A3535C  /*    9 */,
+    0x4CE754918DDEC47C  /*   10 */,    0x0AA2F4DFDC0DF40C  /*   11 */,
+    0x10B76F18A74DBEFA  /*   12 */,    0xC6CCB6235AD1AB6A  /*   13 */,
+    0x13726121572FE2FF  /*   14 */,    0x1A488C6F199D921E  /*   15 */,
+    0x4BC9F9F4DA0007CA  /*   16 */,    0x26F5E6F6E85241C7  /*   17 */,
+    0x859079DBEA5947B6  /*   18 */,    0x4F1885C5C99E8C92  /*   19 */,
+    0xD78E761EA96F864B  /*   20 */,    0x8E36428C52B5C17D  /*   21 */,
+    0x69CF6827373063C1  /*   22 */,    0xB607C93D9BB4C56E  /*   23 */,
+    0x7D820E760E76B5EA  /*   24 */,    0x645C9CC6F07FDC42  /*   25 */,
+    0xBF38A078243342E0  /*   26 */,    0x5F6B343C9D2E7D04  /*   27 */,
+    0xF2C28AEB600B0EC6  /*   28 */,    0x6C0ED85F7254BCAC  /*   29 */,
+    0x71592281A4DB4FE5  /*   30 */,    0x1967FA69CE0FED9F  /*   31 */,
+    0xFD5293F8B96545DB  /*   32 */,    0xC879E9D7F2A7600B  /*   33 */,
+    0x860248920193194E  /*   34 */,    0xA4F9533B2D9CC0B3  /*   35 */,
+    0x9053836C15957613  /*   36 */,    0xDB6DCF8AFC357BF1  /*   37 */,
+    0x18BEEA7A7A370F57  /*   38 */,    0x037117CA50B99066  /*   39 */,
+    0x6AB30A9774424A35  /*   40 */,    0xF4E92F02E325249B  /*   41 */,
+    0x7739DB07061CCAE1  /*   42 */,    0xD8F3B49CECA42A05  /*   43 */,
+    0xBD56BE3F51382F73  /*   44 */,    0x45FAED5843B0BB28  /*   45 */,
+    0x1C813D5C11BF1F83  /*   46 */,    0x8AF0E4B6D75FA169  /*   47 */,
+    0x33EE18A487AD9999  /*   48 */,    0x3C26E8EAB1C94410  /*   49 */,
+    0xB510102BC0A822F9  /*   50 */,    0x141EEF310CE6123B  /*   51 */,
+    0xFC65B90059DDB154  /*   52 */,    0xE0158640C5E0E607  /*   53 */,
+    0x884E079826C3A3CF  /*   54 */,    0x930D0D9523C535FD  /*   55 */,
+    0x35638D754E9A2B00  /*   56 */,    0x4085FCCF40469DD5  /*   57 */,
+    0xC4B17AD28BE23A4C  /*   58 */,    0xCAB2F0FC6A3E6A2E  /*   59 */,
+    0x2860971A6B943FCD  /*   60 */,    0x3DDE6EE212E30446  /*   61 */,
+    0x6222F32AE01765AE  /*   62 */,    0x5D550BB5478308FE  /*   63 */,
+    0xA9EFA98DA0EDA22A  /*   64 */,    0xC351A71686C40DA7  /*   65 */,
+    0x1105586D9C867C84  /*   66 */,    0xDCFFEE85FDA22853  /*   67 */,
+    0xCCFBD0262C5EEF76  /*   68 */,    0xBAF294CB8990D201  /*   69 */,
+    0xE69464F52AFAD975  /*   70 */,    0x94B013AFDF133E14  /*   71 */,
+    0x06A7D1A32823C958  /*   72 */,    0x6F95FE5130F61119  /*   73 */,
+    0xD92AB34E462C06C0  /*   74 */,    0xED7BDE33887C71D2  /*   75 */,
+    0x79746D6E6518393E  /*   76 */,    0x5BA419385D713329  /*   77 */,
+    0x7C1BA6B948A97564  /*   78 */,    0x31987C197BFDAC67  /*   79 */,
+    0xDE6C23C44B053D02  /*   80 */,    0x581C49FED002D64D  /*   81 */,
+    0xDD474D6338261571  /*   82 */,    0xAA4546C3E473D062  /*   83 */,
+    0x928FCE349455F860  /*   84 */,    0x48161BBACAAB94D9  /*   85 */,
+    0x63912430770E6F68  /*   86 */,    0x6EC8A5E602C6641C  /*   87 */,
+    0x87282515337DDD2B  /*   88 */,    0x2CDA6B42034B701B  /*   89 */,
+    0xB03D37C181CB096D  /*   90 */,    0xE108438266C71C6F  /*   91 */,
+    0x2B3180C7EB51B255  /*   92 */,    0xDF92B82F96C08BBC  /*   93 */,
+    0x5C68C8C0A632F3BA  /*   94 */,    0x5504CC861C3D0556  /*   95 */,
+    0xABBFA4E55FB26B8F  /*   96 */,    0x41848B0AB3BACEB4  /*   97 */,
+    0xB334A273AA445D32  /*   98 */,    0xBCA696F0A85AD881  /*   99 */,
+    0x24F6EC65B528D56C  /*  100 */,    0x0CE1512E90F4524A  /*  101 */,
+    0x4E9DD79D5506D35A  /*  102 */,    0x258905FAC6CE9779  /*  103 */,
+    0x2019295B3E109B33  /*  104 */,    0xF8A9478B73A054CC  /*  105 */,
+    0x2924F2F934417EB0  /*  106 */,    0x3993357D536D1BC4  /*  107 */,
+    0x38A81AC21DB6FF8B  /*  108 */,    0x47C4FBF17D6016BF  /*  109 */,
+    0x1E0FAADD7667E3F5  /*  110 */,    0x7ABCFF62938BEB96  /*  111 */,
+    0xA78DAD948FC179C9  /*  112 */,    0x8F1F98B72911E50D  /*  113 */,
+    0x61E48EAE27121A91  /*  114 */,    0x4D62F7AD31859808  /*  115 */,
+    0xECEBA345EF5CEAEB  /*  116 */,    0xF5CEB25EBC9684CE  /*  117 */,
+    0xF633E20CB7F76221  /*  118 */,    0xA32CDF06AB8293E4  /*  119 */,
+    0x985A202CA5EE2CA4  /*  120 */,    0xCF0B8447CC8A8FB1  /*  121 */,
+    0x9F765244979859A3  /*  122 */,    0xA8D516B1A1240017  /*  123 */,
+    0x0BD7BA3EBB5DC726  /*  124 */,    0xE54BCA55B86ADB39  /*  125 */,
+    0x1D7A3AFD6C478063  /*  126 */,    0x519EC608E7669EDD  /*  127 */,
+    0x0E5715A2D149AA23  /*  128 */,    0x177D4571848FF194  /*  129 */,
+    0xEEB55F3241014C22  /*  130 */,    0x0F5E5CA13A6E2EC2  /*  131 */,
+    0x8029927B75F5C361  /*  132 */,    0xAD139FABC3D6E436  /*  133 */,
+    0x0D5DF1A94CCF402F  /*  134 */,    0x3E8BD948BEA5DFC8  /*  135 */,
+    0xA5A0D357BD3FF77E  /*  136 */,    0xA2D12E251F74F645  /*  137 */,
+    0x66FD9E525E81A082  /*  138 */,    0x2E0C90CE7F687A49  /*  139 */,
+    0xC2E8BCBEBA973BC5  /*  140 */,    0x000001BCE509745F  /*  141 */,
+    0x423777BBE6DAB3D6  /*  142 */,    0xD1661C7EAEF06EB5  /*  143 */,
+    0xA1781F354DAACFD8  /*  144 */,    0x2D11284A2B16AFFC  /*  145 */,
+    0xF1FC4F67FA891D1F  /*  146 */,    0x73ECC25DCB920ADA  /*  147 */,
+    0xAE610C22C2A12651  /*  148 */,    0x96E0A810D356B78A  /*  149 */,
+    0x5A9A381F2FE7870F  /*  150 */,    0xD5AD62EDE94E5530  /*  151 */,
+    0xD225E5E8368D1427  /*  152 */,    0x65977B70C7AF4631  /*  153 */,
+    0x99F889B2DE39D74F  /*  154 */,    0x233F30BF54E1D143  /*  155 */,
+    0x9A9675D3D9A63C97  /*  156 */,    0x5470554FF334F9A8  /*  157 */,
+    0x166ACB744A4F5688  /*  158 */,    0x70C74CAAB2E4AEAD  /*  159 */,
+    0xF0D091646F294D12  /*  160 */,    0x57B82A89684031D1  /*  161 */,
+    0xEFD95A5A61BE0B6B  /*  162 */,    0x2FBD12E969F2F29A  /*  163 */,
+    0x9BD37013FEFF9FE8  /*  164 */,    0x3F9B0404D6085A06  /*  165 */,
+    0x4940C1F3166CFE15  /*  166 */,    0x09542C4DCDF3DEFB  /*  167 */,
+    0xB4C5218385CD5CE3  /*  168 */,    0xC935B7DC4462A641  /*  169 */,
+    0x3417F8A68ED3B63F  /*  170 */,    0xB80959295B215B40  /*  171 */,
+    0xF99CDAEF3B8C8572  /*  172 */,    0x018C0614F8FCB95D  /*  173 */,
+    0x1B14ACCD1A3ACDF3  /*  174 */,    0x84D471F200BB732D  /*  175 */,
+    0xC1A3110E95E8DA16  /*  176 */,    0x430A7220BF1A82B8  /*  177 */,
+    0xB77E090D39DF210E  /*  178 */,    0x5EF4BD9F3CD05E9D  /*  179 */,
+    0x9D4FF6DA7E57A444  /*  180 */,    0xDA1D60E183D4A5F8  /*  181 */,
+    0xB287C38417998E47  /*  182 */,    0xFE3EDC121BB31886  /*  183 */,
+    0xC7FE3CCC980CCBEF  /*  184 */,    0xE46FB590189BFD03  /*  185 */,
+    0x3732FD469A4C57DC  /*  186 */,    0x7EF700A07CF1AD65  /*  187 */,
+    0x59C64468A31D8859  /*  188 */,    0x762FB0B4D45B61F6  /*  189 */,
+    0x155BAED099047718  /*  190 */,    0x68755E4C3D50BAA6  /*  191 */,
+    0xE9214E7F22D8B4DF  /*  192 */,    0x2ADDBF532EAC95F4  /*  193 */,
+    0x32AE3909B4BD0109  /*  194 */,    0x834DF537B08E3450  /*  195 */,
+    0xFA209DA84220728D  /*  196 */,    0x9E691D9B9EFE23F7  /*  197 */,
+    0x0446D288C4AE8D7F  /*  198 */,    0x7B4CC524E169785B  /*  199 */,
+    0x21D87F0135CA1385  /*  200 */,    0xCEBB400F137B8AA5  /*  201 */,
+    0x272E2B66580796BE  /*  202 */,    0x3612264125C2B0DE  /*  203 */,
+    0x057702BDAD1EFBB2  /*  204 */,    0xD4BABB8EACF84BE9  /*  205 */,
+    0x91583139641BC67B  /*  206 */,    0x8BDC2DE08036E024  /*  207 */,
+    0x603C8156F49F68ED  /*  208 */,    0xF7D236F7DBEF5111  /*  209 */,
+    0x9727C4598AD21E80  /*  210 */,    0xA08A0896670A5FD7  /*  211 */,
+    0xCB4A8F4309EBA9CB  /*  212 */,    0x81AF564B0F7036A1  /*  213 */,
+    0xC0B99AA778199ABD  /*  214 */,    0x959F1EC83FC8E952  /*  215 */,
+    0x8C505077794A81B9  /*  216 */,    0x3ACAAF8F056338F0  /*  217 */,
+    0x07B43F50627A6778  /*  218 */,    0x4A44AB49F5ECCC77  /*  219 */,
+    0x3BC3D6E4B679EE98  /*  220 */,    0x9CC0D4D1CF14108C  /*  221 */,
+    0x4406C00B206BC8A0  /*  222 */,    0x82A18854C8D72D89  /*  223 */,
+    0x67E366B35C3C432C  /*  224 */,    0xB923DD61102B37F2  /*  225 */,
+    0x56AB2779D884271D  /*  226 */,    0xBE83E1B0FF1525AF  /*  227 */,
+    0xFB7C65D4217E49A9  /*  228 */,    0x6BDBE0E76D48E7D4  /*  229 */,
+    0x08DF828745D9179E  /*  230 */,    0x22EA6A9ADD53BD34  /*  231 */,
+    0xE36E141C5622200A  /*  232 */,    0x7F805D1B8CB750EE  /*  233 */,
+    0xAFE5C7A59F58E837  /*  234 */,    0xE27F996A4FB1C23C  /*  235 */,
+    0xD3867DFB0775F0D0  /*  236 */,    0xD0E673DE6E88891A  /*  237 */,
+    0x123AEB9EAFB86C25  /*  238 */,    0x30F1D5D5C145B895  /*  239 */,
+    0xBB434A2DEE7269E7  /*  240 */,    0x78CB67ECF931FA38  /*  241 */,
+    0xF33B0372323BBF9C  /*  242 */,    0x52D66336FB279C74  /*  243 */,
+    0x505F33AC0AFB4EAA  /*  244 */,    0xE8A5CD99A2CCE187  /*  245 */,
+    0x534974801E2D30BB  /*  246 */,    0x8D2D5711D5876D90  /*  247 */,
+    0x1F1A412891BC038E  /*  248 */,    0xD6E2E71D82E56648  /*  249 */,
+    0x74036C3A497732B7  /*  250 */,    0x89B67ED96361F5AB  /*  251 */,
+    0xFFED95D8F1EA02A2  /*  252 */,    0xE72B3BD61464D43D  /*  253 */,
+    0xA6300F170BDC4820  /*  254 */,    0xEBC18760ED78A77A  /*  255 */,
+    0xE6A6BE5A05A12138  /*  256 */,    0xB5A122A5B4F87C98  /*  257 */,
+    0x563C6089140B6990  /*  258 */,    0x4C46CB2E391F5DD5  /*  259 */,
+    0xD932ADDBC9B79434  /*  260 */,    0x08EA70E42015AFF5  /*  261 */,
+    0xD765A6673E478CF1  /*  262 */,    0xC4FB757EAB278D99  /*  263 */,
+    0xDF11C6862D6E0692  /*  264 */,    0xDDEB84F10D7F3B16  /*  265 */,
+    0x6F2EF604A665EA04  /*  266 */,    0x4A8E0F0FF0E0DFB3  /*  267 */,
+    0xA5EDEEF83DBCBA51  /*  268 */,    0xFC4F0A2A0EA4371E  /*  269 */,
+    0xE83E1DA85CB38429  /*  270 */,    0xDC8FF882BA1B1CE2  /*  271 */,
+    0xCD45505E8353E80D  /*  272 */,    0x18D19A00D4DB0717  /*  273 */,
+    0x34A0CFEDA5F38101  /*  274 */,    0x0BE77E518887CAF2  /*  275 */,
+    0x1E341438B3C45136  /*  276 */,    0xE05797F49089CCF9  /*  277 */,
+    0xFFD23F9DF2591D14  /*  278 */,    0x543DDA228595C5CD  /*  279 */,
+    0x661F81FD99052A33  /*  280 */,    0x8736E641DB0F7B76  /*  281 */,
+    0x15227725418E5307  /*  282 */,    0xE25F7F46162EB2FA  /*  283 */,
+    0x48A8B2126C13D9FE  /*  284 */,    0xAFDC541792E76EEA  /*  285 */,
+    0x03D912BFC6D1898F  /*  286 */,    0x31B1AAFA1B83F51B  /*  287 */,
+    0xF1AC2796E42AB7D9  /*  288 */,    0x40A3A7D7FCD2EBAC  /*  289 */,
+    0x1056136D0AFBBCC5  /*  290 */,    0x7889E1DD9A6D0C85  /*  291 */,
+    0xD33525782A7974AA  /*  292 */,    0xA7E25D09078AC09B  /*  293 */,
+    0xBD4138B3EAC6EDD0  /*  294 */,    0x920ABFBE71EB9E70  /*  295 */,
+    0xA2A5D0F54FC2625C  /*  296 */,    0xC054E36B0B1290A3  /*  297 */,
+    0xF6DD59FF62FE932B  /*  298 */,    0x3537354511A8AC7D  /*  299 */,
+    0xCA845E9172FADCD4  /*  300 */,    0x84F82B60329D20DC  /*  301 */,
+    0x79C62CE1CD672F18  /*  302 */,    0x8B09A2ADD124642C  /*  303 */,
+    0xD0C1E96A19D9E726  /*  304 */,    0x5A786A9B4BA9500C  /*  305 */,
+    0x0E020336634C43F3  /*  306 */,    0xC17B474AEB66D822  /*  307 */,
+    0x6A731AE3EC9BAAC2  /*  308 */,    0x8226667AE0840258  /*  309 */,
+    0x67D4567691CAECA5  /*  310 */,    0x1D94155C4875ADB5  /*  311 */,
+    0x6D00FD985B813FDF  /*  312 */,    0x51286EFCB774CD06  /*  313 */,
+    0x5E8834471FA744AF  /*  314 */,    0xF72CA0AEE761AE2E  /*  315 */,
+    0xBE40E4CDAEE8E09A  /*  316 */,    0xE9970BBB5118F665  /*  317 */,
+    0x726E4BEB33DF1964  /*  318 */,    0x703B000729199762  /*  319 */,
+    0x4631D816F5EF30A7  /*  320 */,    0xB880B5B51504A6BE  /*  321 */,
+    0x641793C37ED84B6C  /*  322 */,    0x7B21ED77F6E97D96  /*  323 */,
+    0x776306312EF96B73  /*  324 */,    0xAE528948E86FF3F4  /*  325 */,
+    0x53DBD7F286A3F8F8  /*  326 */,    0x16CADCE74CFC1063  /*  327 */,
+    0x005C19BDFA52C6DD  /*  328 */,    0x68868F5D64D46AD3  /*  329 */,
+    0x3A9D512CCF1E186A  /*  330 */,    0x367E62C2385660AE  /*  331 */,
+    0xE359E7EA77DCB1D7  /*  332 */,    0x526C0773749ABE6E  /*  333 */,
+    0x735AE5F9D09F734B  /*  334 */,    0x493FC7CC8A558BA8  /*  335 */,
+    0xB0B9C1533041AB45  /*  336 */,    0x321958BA470A59BD  /*  337 */,
+    0x852DB00B5F46C393  /*  338 */,    0x91209B2BD336B0E5  /*  339 */,
+    0x6E604F7D659EF19F  /*  340 */,    0xB99A8AE2782CCB24  /*  341 */,
+    0xCCF52AB6C814C4C7  /*  342 */,    0x4727D9AFBE11727B  /*  343 */,
+    0x7E950D0C0121B34D  /*  344 */,    0x756F435670AD471F  /*  345 */,
+    0xF5ADD442615A6849  /*  346 */,    0x4E87E09980B9957A  /*  347 */,
+    0x2ACFA1DF50AEE355  /*  348 */,    0xD898263AFD2FD556  /*  349 */,
+    0xC8F4924DD80C8FD6  /*  350 */,    0xCF99CA3D754A173A  /*  351 */,
+    0xFE477BACAF91BF3C  /*  352 */,    0xED5371F6D690C12D  /*  353 */,
+    0x831A5C285E687094  /*  354 */,    0xC5D3C90A3708A0A4  /*  355 */,
+    0x0F7F903717D06580  /*  356 */,    0x19F9BB13B8FDF27F  /*  357 */,
+    0xB1BD6F1B4D502843  /*  358 */,    0x1C761BA38FFF4012  /*  359 */,
+    0x0D1530C4E2E21F3B  /*  360 */,    0x8943CE69A7372C8A  /*  361 */,
+    0xE5184E11FEB5CE66  /*  362 */,    0x618BDB80BD736621  /*  363 */,
+    0x7D29BAD68B574D0B  /*  364 */,    0x81BB613E25E6FE5B  /*  365 */,
+    0x071C9C10BC07913F  /*  366 */,    0xC7BEEB7909AC2D97  /*  367 */,
+    0xC3E58D353BC5D757  /*  368 */,    0xEB017892F38F61E8  /*  369 */,
+    0xD4EFFB9C9B1CC21A  /*  370 */,    0x99727D26F494F7AB  /*  371 */,
+    0xA3E063A2956B3E03  /*  372 */,    0x9D4A8B9A4AA09C30  /*  373 */,
+    0x3F6AB7D500090FB4  /*  374 */,    0x9CC0F2A057268AC0  /*  375 */,
+    0x3DEE9D2DEDBF42D1  /*  376 */,    0x330F49C87960A972  /*  377 */,
+    0xC6B2720287421B41  /*  378 */,    0x0AC59EC07C00369C  /*  379 */,
+    0xEF4EAC49CB353425  /*  380 */,    0xF450244EEF0129D8  /*  381 */,
+    0x8ACC46E5CAF4DEB6  /*  382 */,    0x2FFEAB63989263F7  /*  383 */,
+    0x8F7CB9FE5D7A4578  /*  384 */,    0x5BD8F7644E634635  /*  385 */,
+    0x427A7315BF2DC900  /*  386 */,    0x17D0C4AA2125261C  /*  387 */,
+    0x3992486C93518E50  /*  388 */,    0xB4CBFEE0A2D7D4C3  /*  389 */,
+    0x7C75D6202C5DDD8D  /*  390 */,    0xDBC295D8E35B6C61  /*  391 */,
+    0x60B369D302032B19  /*  392 */,    0xCE42685FDCE44132  /*  393 */,
+    0x06F3DDB9DDF65610  /*  394 */,    0x8EA4D21DB5E148F0  /*  395 */,
+    0x20B0FCE62FCD496F  /*  396 */,    0x2C1B912358B0EE31  /*  397 */,
+    0xB28317B818F5A308  /*  398 */,    0xA89C1E189CA6D2CF  /*  399 */,
+    0x0C6B18576AAADBC8  /*  400 */,    0xB65DEAA91299FAE3  /*  401 */,
+    0xFB2B794B7F1027E7  /*  402 */,    0x04E4317F443B5BEB  /*  403 */,
+    0x4B852D325939D0A6  /*  404 */,    0xD5AE6BEEFB207FFC  /*  405 */,
+    0x309682B281C7D374  /*  406 */,    0xBAE309A194C3B475  /*  407 */,
+    0x8CC3F97B13B49F05  /*  408 */,    0x98A9422FF8293967  /*  409 */,
+    0x244B16B01076FF7C  /*  410 */,    0xF8BF571C663D67EE  /*  411 */,
+    0x1F0D6758EEE30DA1  /*  412 */,    0xC9B611D97ADEB9B7  /*  413 */,
+    0xB7AFD5887B6C57A2  /*  414 */,    0x6290AE846B984FE1  /*  415 */,
+    0x94DF4CDEACC1A5FD  /*  416 */,    0x058A5BD1C5483AFF  /*  417 */,
+    0x63166CC142BA3C37  /*  418 */,    0x8DB8526EB2F76F40  /*  419 */,
+    0xE10880036F0D6D4E  /*  420 */,    0x9E0523C9971D311D  /*  421 */,
+    0x45EC2824CC7CD691  /*  422 */,    0x575B8359E62382C9  /*  423 */,
+    0xFA9E400DC4889995  /*  424 */,    0xD1823ECB45721568  /*  425 */,
+    0xDAFD983B8206082F  /*  426 */,    0xAA7D29082386A8CB  /*  427 */,
+    0x269FCD4403B87588  /*  428 */,    0x1B91F5F728BDD1E0  /*  429 */,
+    0xE4669F39040201F6  /*  430 */,    0x7A1D7C218CF04ADE  /*  431 */,
+    0x65623C29D79CE5CE  /*  432 */,    0x2368449096C00BB1  /*  433 */,
+    0xAB9BF1879DA503BA  /*  434 */,    0xBC23ECB1A458058E  /*  435 */,
+    0x9A58DF01BB401ECC  /*  436 */,    0xA070E868A85F143D  /*  437 */,
+    0x4FF188307DF2239E  /*  438 */,    0x14D565B41A641183  /*  439 */,
+    0xEE13337452701602  /*  440 */,    0x950E3DCF3F285E09  /*  441 */,
+    0x59930254B9C80953  /*  442 */,    0x3BF299408930DA6D  /*  443 */,
+    0xA955943F53691387  /*  444 */,    0xA15EDECAA9CB8784  /*  445 */,
+    0x29142127352BE9A0  /*  446 */,    0x76F0371FFF4E7AFB  /*  447 */,
+    0x0239F450274F2228  /*  448 */,    0xBB073AF01D5E868B  /*  449 */,
+    0xBFC80571C10E96C1  /*  450 */,    0xD267088568222E23  /*  451 */,
+    0x9671A3D48E80B5B0  /*  452 */,    0x55B5D38AE193BB81  /*  453 */,
+    0x693AE2D0A18B04B8  /*  454 */,    0x5C48B4ECADD5335F  /*  455 */,
+    0xFD743B194916A1CA  /*  456 */,    0x2577018134BE98C4  /*  457 */,
+    0xE77987E83C54A4AD  /*  458 */,    0x28E11014DA33E1B9  /*  459 */,
+    0x270CC59E226AA213  /*  460 */,    0x71495F756D1A5F60  /*  461 */,
+    0x9BE853FB60AFEF77  /*  462 */,    0xADC786A7F7443DBF  /*  463 */,
+    0x0904456173B29A82  /*  464 */,    0x58BC7A66C232BD5E  /*  465 */,
+    0xF306558C673AC8B2  /*  466 */,    0x41F639C6B6C9772A  /*  467 */,
+    0x216DEFE99FDA35DA  /*  468 */,    0x11640CC71C7BE615  /*  469 */,
+    0x93C43694565C5527  /*  470 */,    0xEA038E6246777839  /*  471 */,
+    0xF9ABF3CE5A3E2469  /*  472 */,    0x741E768D0FD312D2  /*  473 */,
+    0x0144B883CED652C6  /*  474 */,    0xC20B5A5BA33F8552  /*  475 */,
+    0x1AE69633C3435A9D  /*  476 */,    0x97A28CA4088CFDEC  /*  477 */,
+    0x8824A43C1E96F420  /*  478 */,    0x37612FA66EEEA746  /*  479 */,
+    0x6B4CB165F9CF0E5A  /*  480 */,    0x43AA1C06A0ABFB4A  /*  481 */,
+    0x7F4DC26FF162796B  /*  482 */,    0x6CBACC8E54ED9B0F  /*  483 */,
+    0xA6B7FFEFD2BB253E  /*  484 */,    0x2E25BC95B0A29D4F  /*  485 */,
+    0x86D6A58BDEF1388C  /*  486 */,    0xDED74AC576B6F054  /*  487 */,
+    0x8030BDBC2B45805D  /*  488 */,    0x3C81AF70E94D9289  /*  489 */,
+    0x3EFF6DDA9E3100DB  /*  490 */,    0xB38DC39FDFCC8847  /*  491 */,
+    0x123885528D17B87E  /*  492 */,    0xF2DA0ED240B1B642  /*  493 */,
+    0x44CEFADCD54BF9A9  /*  494 */,    0x1312200E433C7EE6  /*  495 */,
+    0x9FFCC84F3A78C748  /*  496 */,    0xF0CD1F72248576BB  /*  497 */,
+    0xEC6974053638CFE4  /*  498 */,    0x2BA7B67C0CEC4E4C  /*  499 */,
+    0xAC2F4DF3E5CE32ED  /*  500 */,    0xCB33D14326EA4C11  /*  501 */,
+    0xA4E9044CC77E58BC  /*  502 */,    0x5F513293D934FCEF  /*  503 */,
+    0x5DC9645506E55444  /*  504 */,    0x50DE418F317DE40A  /*  505 */,
+    0x388CB31A69DDE259  /*  506 */,    0x2DB4A83455820A86  /*  507 */,
+    0x9010A91E84711AE9  /*  508 */,    0x4DF7F0B7B1498371  /*  509 */,
+    0xD62A2EABC0977179  /*  510 */,    0x22FAC097AA8D5C0E  /*  511 */,
+    0xF49FCC2FF1DAF39B  /*  512 */,    0x487FD5C66FF29281  /*  513 */,
+    0xE8A30667FCDCA83F  /*  514 */,    0x2C9B4BE3D2FCCE63  /*  515 */,
+    0xDA3FF74B93FBBBC2  /*  516 */,    0x2FA165D2FE70BA66  /*  517 */,
+    0xA103E279970E93D4  /*  518 */,    0xBECDEC77B0E45E71  /*  519 */,
+    0xCFB41E723985E497  /*  520 */,    0xB70AAA025EF75017  /*  521 */,
+    0xD42309F03840B8E0  /*  522 */,    0x8EFC1AD035898579  /*  523 */,
+    0x96C6920BE2B2ABC5  /*  524 */,    0x66AF4163375A9172  /*  525 */,
+    0x2174ABDCCA7127FB  /*  526 */,    0xB33CCEA64A72FF41  /*  527 */,
+    0xF04A4933083066A5  /*  528 */,    0x8D970ACDD7289AF5  /*  529 */,
+    0x8F96E8E031C8C25E  /*  530 */,    0xF3FEC02276875D47  /*  531 */,
+    0xEC7BF310056190DD  /*  532 */,    0xF5ADB0AEBB0F1491  /*  533 */,
+    0x9B50F8850FD58892  /*  534 */,    0x4975488358B74DE8  /*  535 */,
+    0xA3354FF691531C61  /*  536 */,    0x0702BBE481D2C6EE  /*  537 */,
+    0x89FB24057DEDED98  /*  538 */,    0xAC3075138596E902  /*  539 */,
+    0x1D2D3580172772ED  /*  540 */,    0xEB738FC28E6BC30D  /*  541 */,
+    0x5854EF8F63044326  /*  542 */,    0x9E5C52325ADD3BBE  /*  543 */,
+    0x90AA53CF325C4623  /*  544 */,    0xC1D24D51349DD067  /*  545 */,
+    0x2051CFEEA69EA624  /*  546 */,    0x13220F0A862E7E4F  /*  547 */,
+    0xCE39399404E04864  /*  548 */,    0xD9C42CA47086FCB7  /*  549 */,
+    0x685AD2238A03E7CC  /*  550 */,    0x066484B2AB2FF1DB  /*  551 */,
+    0xFE9D5D70EFBF79EC  /*  552 */,    0x5B13B9DD9C481854  /*  553 */,
+    0x15F0D475ED1509AD  /*  554 */,    0x0BEBCD060EC79851  /*  555 */,
+    0xD58C6791183AB7F8  /*  556 */,    0xD1187C5052F3EEE4  /*  557 */,
+    0xC95D1192E54E82FF  /*  558 */,    0x86EEA14CB9AC6CA2  /*  559 */,
+    0x3485BEB153677D5D  /*  560 */,    0xDD191D781F8C492A  /*  561 */,
+    0xF60866BAA784EBF9  /*  562 */,    0x518F643BA2D08C74  /*  563 */,
+    0x8852E956E1087C22  /*  564 */,    0xA768CB8DC410AE8D  /*  565 */,
+    0x38047726BFEC8E1A  /*  566 */,    0xA67738B4CD3B45AA  /*  567 */,
+    0xAD16691CEC0DDE19  /*  568 */,    0xC6D4319380462E07  /*  569 */,
+    0xC5A5876D0BA61938  /*  570 */,    0x16B9FA1FA58FD840  /*  571 */,
+    0x188AB1173CA74F18  /*  572 */,    0xABDA2F98C99C021F  /*  573 */,
+    0x3E0580AB134AE816  /*  574 */,    0x5F3B05B773645ABB  /*  575 */,
+    0x2501A2BE5575F2F6  /*  576 */,    0x1B2F74004E7E8BA9  /*  577 */,
+    0x1CD7580371E8D953  /*  578 */,    0x7F6ED89562764E30  /*  579 */,
+    0xB15926FF596F003D  /*  580 */,    0x9F65293DA8C5D6B9  /*  581 */,
+    0x6ECEF04DD690F84C  /*  582 */,    0x4782275FFF33AF88  /*  583 */,
+    0xE41433083F820801  /*  584 */,    0xFD0DFE409A1AF9B5  /*  585 */,
+    0x4325A3342CDB396B  /*  586 */,    0x8AE77E62B301B252  /*  587 */,
+    0xC36F9E9F6655615A  /*  588 */,    0x85455A2D92D32C09  /*  589 */,
+    0xF2C7DEA949477485  /*  590 */,    0x63CFB4C133A39EBA  /*  591 */,
+    0x83B040CC6EBC5462  /*  592 */,    0x3B9454C8FDB326B0  /*  593 */,
+    0x56F56A9E87FFD78C  /*  594 */,    0x2DC2940D99F42BC6  /*  595 */,
+    0x98F7DF096B096E2D  /*  596 */,    0x19A6E01E3AD852BF  /*  597 */,
+    0x42A99CCBDBD4B40B  /*  598 */,    0xA59998AF45E9C559  /*  599 */,
+    0x366295E807D93186  /*  600 */,    0x6B48181BFAA1F773  /*  601 */,
+    0x1FEC57E2157A0A1D  /*  602 */,    0x4667446AF6201AD5  /*  603 */,
+    0xE615EBCACFB0F075  /*  604 */,    0xB8F31F4F68290778  /*  605 */,
+    0x22713ED6CE22D11E  /*  606 */,    0x3057C1A72EC3C93B  /*  607 */,
+    0xCB46ACC37C3F1F2F  /*  608 */,    0xDBB893FD02AAF50E  /*  609 */,
+    0x331FD92E600B9FCF  /*  610 */,    0xA498F96148EA3AD6  /*  611 */,
+    0xA8D8426E8B6A83EA  /*  612 */,    0xA089B274B7735CDC  /*  613 */,
+    0x87F6B3731E524A11  /*  614 */,    0x118808E5CBC96749  /*  615 */,
+    0x9906E4C7B19BD394  /*  616 */,    0xAFED7F7E9B24A20C  /*  617 */,
+    0x6509EADEEB3644A7  /*  618 */,    0x6C1EF1D3E8EF0EDE  /*  619 */,
+    0xB9C97D43E9798FB4  /*  620 */,    0xA2F2D784740C28A3  /*  621 */,
+    0x7B8496476197566F  /*  622 */,    0x7A5BE3E6B65F069D  /*  623 */,
+    0xF96330ED78BE6F10  /*  624 */,    0xEEE60DE77A076A15  /*  625 */,
+    0x2B4BEE4AA08B9BD0  /*  626 */,    0x6A56A63EC7B8894E  /*  627 */,
+    0x02121359BA34FEF4  /*  628 */,    0x4CBF99F8283703FC  /*  629 */,
+    0x398071350CAF30C8  /*  630 */,    0xD0A77A89F017687A  /*  631 */,
+    0xF1C1A9EB9E423569  /*  632 */,    0x8C7976282DEE8199  /*  633 */,
+    0x5D1737A5DD1F7ABD  /*  634 */,    0x4F53433C09A9FA80  /*  635 */,
+    0xFA8B0C53DF7CA1D9  /*  636 */,    0x3FD9DCBC886CCB77  /*  637 */,
+    0xC040917CA91B4720  /*  638 */,    0x7DD00142F9D1DCDF  /*  639 */,
+    0x8476FC1D4F387B58  /*  640 */,    0x23F8E7C5F3316503  /*  641 */,
+    0x032A2244E7E37339  /*  642 */,    0x5C87A5D750F5A74B  /*  643 */,
+    0x082B4CC43698992E  /*  644 */,    0xDF917BECB858F63C  /*  645 */,
+    0x3270B8FC5BF86DDA  /*  646 */,    0x10AE72BB29B5DD76  /*  647 */,
+    0x576AC94E7700362B  /*  648 */,    0x1AD112DAC61EFB8F  /*  649 */,
+    0x691BC30EC5FAA427  /*  650 */,    0xFF246311CC327143  /*  651 */,
+    0x3142368E30E53206  /*  652 */,    0x71380E31E02CA396  /*  653 */,
+    0x958D5C960AAD76F1  /*  654 */,    0xF8D6F430C16DA536  /*  655 */,
+    0xC8FFD13F1BE7E1D2  /*  656 */,    0x7578AE66004DDBE1  /*  657 */,
+    0x05833F01067BE646  /*  658 */,    0xBB34B5AD3BFE586D  /*  659 */,
+    0x095F34C9A12B97F0  /*  660 */,    0x247AB64525D60CA8  /*  661 */,
+    0xDCDBC6F3017477D1  /*  662 */,    0x4A2E14D4DECAD24D  /*  663 */,
+    0xBDB5E6D9BE0A1EEB  /*  664 */,    0x2A7E70F7794301AB  /*  665 */,
+    0xDEF42D8A270540FD  /*  666 */,    0x01078EC0A34C22C1  /*  667 */,
+    0xE5DE511AF4C16387  /*  668 */,    0x7EBB3A52BD9A330A  /*  669 */,
+    0x77697857AA7D6435  /*  670 */,    0x004E831603AE4C32  /*  671 */,
+    0xE7A21020AD78E312  /*  672 */,    0x9D41A70C6AB420F2  /*  673 */,
+    0x28E06C18EA1141E6  /*  674 */,    0xD2B28CBD984F6B28  /*  675 */,
+    0x26B75F6C446E9D83  /*  676 */,    0xBA47568C4D418D7F  /*  677 */,
+    0xD80BADBFE6183D8E  /*  678 */,    0x0E206D7F5F166044  /*  679 */,
+    0xE258A43911CBCA3E  /*  680 */,    0x723A1746B21DC0BC  /*  681 */,
+    0xC7CAA854F5D7CDD3  /*  682 */,    0x7CAC32883D261D9C  /*  683 */,
+    0x7690C26423BA942C  /*  684 */,    0x17E55524478042B8  /*  685 */,
+    0xE0BE477656A2389F  /*  686 */,    0x4D289B5E67AB2DA0  /*  687 */,
+    0x44862B9C8FBBFD31  /*  688 */,    0xB47CC8049D141365  /*  689 */,
+    0x822C1B362B91C793  /*  690 */,    0x4EB14655FB13DFD8  /*  691 */,
+    0x1ECBBA0714E2A97B  /*  692 */,    0x6143459D5CDE5F14  /*  693 */,
+    0x53A8FBF1D5F0AC89  /*  694 */,    0x97EA04D81C5E5B00  /*  695 */,
+    0x622181A8D4FDB3F3  /*  696 */,    0xE9BCD341572A1208  /*  697 */,
+    0x1411258643CCE58A  /*  698 */,    0x9144C5FEA4C6E0A4  /*  699 */,
+    0x0D33D06565CF620F  /*  700 */,    0x54A48D489F219CA1  /*  701 */,
+    0xC43E5EAC6D63C821  /*  702 */,    0xA9728B3A72770DAF  /*  703 */,
+    0xD7934E7B20DF87EF  /*  704 */,    0xE35503B61A3E86E5  /*  705 */,
+    0xCAE321FBC819D504  /*  706 */,    0x129A50B3AC60BFA6  /*  707 */,
+    0xCD5E68EA7E9FB6C3  /*  708 */,    0xB01C90199483B1C7  /*  709 */,
+    0x3DE93CD5C295376C  /*  710 */,    0xAED52EDF2AB9AD13  /*  711 */,
+    0x2E60F512C0A07884  /*  712 */,    0xBC3D86A3E36210C9  /*  713 */,
+    0x35269D9B163951CE  /*  714 */,    0x0C7D6E2AD0CDB5FA  /*  715 */,
+    0x59E86297D87F5733  /*  716 */,    0x298EF221898DB0E7  /*  717 */,
+    0x55000029D1A5AA7E  /*  718 */,    0x8BC08AE1B5061B45  /*  719 */,
+    0xC2C31C2B6C92703A  /*  720 */,    0x94CC596BAF25EF42  /*  721 */,
+    0x0A1D73DB22540456  /*  722 */,    0x04B6A0F9D9C4179A  /*  723 */,
+    0xEFFDAFA2AE3D3C60  /*  724 */,    0xF7C8075BB49496C4  /*  725 */,
+    0x9CC5C7141D1CD4E3  /*  726 */,    0x78BD1638218E5534  /*  727 */,
+    0xB2F11568F850246A  /*  728 */,    0xEDFABCFA9502BC29  /*  729 */,
+    0x796CE5F2DA23051B  /*  730 */,    0xAAE128B0DC93537C  /*  731 */,
+    0x3A493DA0EE4B29AE  /*  732 */,    0xB5DF6B2C416895D7  /*  733 */,
+    0xFCABBD25122D7F37  /*  734 */,    0x70810B58105DC4B1  /*  735 */,
+    0xE10FDD37F7882A90  /*  736 */,    0x524DCAB5518A3F5C  /*  737 */,
+    0x3C9E85878451255B  /*  738 */,    0x4029828119BD34E2  /*  739 */,
+    0x74A05B6F5D3CECCB  /*  740 */,    0xB610021542E13ECA  /*  741 */,
+    0x0FF979D12F59E2AC  /*  742 */,    0x6037DA27E4F9CC50  /*  743 */,
+    0x5E92975A0DF1847D  /*  744 */,    0xD66DE190D3E623FE  /*  745 */,
+    0x5032D6B87B568048  /*  746 */,    0x9A36B7CE8235216E  /*  747 */,
+    0x80272A7A24F64B4A  /*  748 */,    0x93EFED8B8C6916F7  /*  749 */,
+    0x37DDBFF44CCE1555  /*  750 */,    0x4B95DB5D4B99BD25  /*  751 */,
+    0x92D3FDA169812FC0  /*  752 */,    0xFB1A4A9A90660BB6  /*  753 */,
+    0x730C196946A4B9B2  /*  754 */,    0x81E289AA7F49DA68  /*  755 */,
+    0x64669A0F83B1A05F  /*  756 */,    0x27B3FF7D9644F48B  /*  757 */,
+    0xCC6B615C8DB675B3  /*  758 */,    0x674F20B9BCEBBE95  /*  759 */,
+    0x6F31238275655982  /*  760 */,    0x5AE488713E45CF05  /*  761 */,
+    0xBF619F9954C21157  /*  762 */,    0xEABAC46040A8EAE9  /*  763 */,
+    0x454C6FE9F2C0C1CD  /*  764 */,    0x419CF6496412691C  /*  765 */,
+    0xD3DC3BEF265B0F70  /*  766 */,    0x6D0E60F5C3578A9E  /*  767 */,
+    0x5B0E608526323C55  /*  768 */,    0x1A46C1A9FA1B59F5  /*  769 */,
+    0xA9E245A17C4C8FFA  /*  770 */,    0x65CA5159DB2955D7  /*  771 */,
+    0x05DB0A76CE35AFC2  /*  772 */,    0x81EAC77EA9113D45  /*  773 */,
+    0x528EF88AB6AC0A0D  /*  774 */,    0xA09EA253597BE3FF  /*  775 */,
+    0x430DDFB3AC48CD56  /*  776 */,    0xC4B3A67AF45CE46F  /*  777 */,
+    0x4ECECFD8FBE2D05E  /*  778 */,    0x3EF56F10B39935F0  /*  779 */,
+    0x0B22D6829CD619C6  /*  780 */,    0x17FD460A74DF2069  /*  781 */,
+    0x6CF8CC8E8510ED40  /*  782 */,    0xD6C824BF3A6ECAA7  /*  783 */,
+    0x61243D581A817049  /*  784 */,    0x048BACB6BBC163A2  /*  785 */,
+    0xD9A38AC27D44CC32  /*  786 */,    0x7FDDFF5BAAF410AB  /*  787 */,
+    0xAD6D495AA804824B  /*  788 */,    0xE1A6A74F2D8C9F94  /*  789 */,
+    0xD4F7851235DEE8E3  /*  790 */,    0xFD4B7F886540D893  /*  791 */,
+    0x247C20042AA4BFDA  /*  792 */,    0x096EA1C517D1327C  /*  793 */,
+    0xD56966B4361A6685  /*  794 */,    0x277DA5C31221057D  /*  795 */,
+    0x94D59893A43ACFF7  /*  796 */,    0x64F0C51CCDC02281  /*  797 */,
+    0x3D33BCC4FF6189DB  /*  798 */,    0xE005CB184CE66AF1  /*  799 */,
+    0xFF5CCD1D1DB99BEA  /*  800 */,    0xB0B854A7FE42980F  /*  801 */,
+    0x7BD46A6A718D4B9F  /*  802 */,    0xD10FA8CC22A5FD8C  /*  803 */,
+    0xD31484952BE4BD31  /*  804 */,    0xC7FA975FCB243847  /*  805 */,
+    0x4886ED1E5846C407  /*  806 */,    0x28CDDB791EB70B04  /*  807 */,
+    0xC2B00BE2F573417F  /*  808 */,    0x5C9590452180F877  /*  809 */,
+    0x7A6BDDFFF370EB00  /*  810 */,    0xCE509E38D6D9D6A4  /*  811 */,
+    0xEBEB0F00647FA702  /*  812 */,    0x1DCC06CF76606F06  /*  813 */,
+    0xE4D9F28BA286FF0A  /*  814 */,    0xD85A305DC918C262  /*  815 */,
+    0x475B1D8732225F54  /*  816 */,    0x2D4FB51668CCB5FE  /*  817 */,
+    0xA679B9D9D72BBA20  /*  818 */,    0x53841C0D912D43A5  /*  819 */,
+    0x3B7EAA48BF12A4E8  /*  820 */,    0x781E0E47F22F1DDF  /*  821 */,
+    0xEFF20CE60AB50973  /*  822 */,    0x20D261D19DFFB742  /*  823 */,
+    0x16A12B03062A2E39  /*  824 */,    0x1960EB2239650495  /*  825 */,
+    0x251C16FED50EB8B8  /*  826 */,    0x9AC0C330F826016E  /*  827 */,
+    0xED152665953E7671  /*  828 */,    0x02D63194A6369570  /*  829 */,
+    0x5074F08394B1C987  /*  830 */,    0x70BA598C90B25CE1  /*  831 */,
+    0x794A15810B9742F6  /*  832 */,    0x0D5925E9FCAF8C6C  /*  833 */,
+    0x3067716CD868744E  /*  834 */,    0x910AB077E8D7731B  /*  835 */,
+    0x6A61BBDB5AC42F61  /*  836 */,    0x93513EFBF0851567  /*  837 */,
+    0xF494724B9E83E9D5  /*  838 */,    0xE887E1985C09648D  /*  839 */,
+    0x34B1D3C675370CFD  /*  840 */,    0xDC35E433BC0D255D  /*  841 */,
+    0xD0AAB84234131BE0  /*  842 */,    0x08042A50B48B7EAF  /*  843 */,
+    0x9997C4EE44A3AB35  /*  844 */,    0x829A7B49201799D0  /*  845 */,
+    0x263B8307B7C54441  /*  846 */,    0x752F95F4FD6A6CA6  /*  847 */,
+    0x927217402C08C6E5  /*  848 */,    0x2A8AB754A795D9EE  /*  849 */,
+    0xA442F7552F72943D  /*  850 */,    0x2C31334E19781208  /*  851 */,
+    0x4FA98D7CEAEE6291  /*  852 */,    0x55C3862F665DB309  /*  853 */,
+    0xBD0610175D53B1F3  /*  854 */,    0x46FE6CB840413F27  /*  855 */,
+    0x3FE03792DF0CFA59  /*  856 */,    0xCFE700372EB85E8F  /*  857 */,
+    0xA7BE29E7ADBCE118  /*  858 */,    0xE544EE5CDE8431DD  /*  859 */,
+    0x8A781B1B41F1873E  /*  860 */,    0xA5C94C78A0D2F0E7  /*  861 */,
+    0x39412E2877B60728  /*  862 */,    0xA1265EF3AFC9A62C  /*  863 */,
+    0xBCC2770C6A2506C5  /*  864 */,    0x3AB66DD5DCE1CE12  /*  865 */,
+    0xE65499D04A675B37  /*  866 */,    0x7D8F523481BFD216  /*  867 */,
+    0x0F6F64FCEC15F389  /*  868 */,    0x74EFBE618B5B13C8  /*  869 */,
+    0xACDC82B714273E1D  /*  870 */,    0xDD40BFE003199D17  /*  871 */,
+    0x37E99257E7E061F8  /*  872 */,    0xFA52626904775AAA  /*  873 */,
+    0x8BBBF63A463D56F9  /*  874 */,    0xF0013F1543A26E64  /*  875 */,
+    0xA8307E9F879EC898  /*  876 */,    0xCC4C27A4150177CC  /*  877 */,
+    0x1B432F2CCA1D3348  /*  878 */,    0xDE1D1F8F9F6FA013  /*  879 */,
+    0x606602A047A7DDD6  /*  880 */,    0xD237AB64CC1CB2C7  /*  881 */,
+    0x9B938E7225FCD1D3  /*  882 */,    0xEC4E03708E0FF476  /*  883 */,
+    0xFEB2FBDA3D03C12D  /*  884 */,    0xAE0BCED2EE43889A  /*  885 */,
+    0x22CB8923EBFB4F43  /*  886 */,    0x69360D013CF7396D  /*  887 */,
+    0x855E3602D2D4E022  /*  888 */,    0x073805BAD01F784C  /*  889 */,
+    0x33E17A133852F546  /*  890 */,    0xDF4874058AC7B638  /*  891 */,
+    0xBA92B29C678AA14A  /*  892 */,    0x0CE89FC76CFAADCD  /*  893 */,
+    0x5F9D4E0908339E34  /*  894 */,    0xF1AFE9291F5923B9  /*  895 */,
+    0x6E3480F60F4A265F  /*  896 */,    0xEEBF3A2AB29B841C  /*  897 */,
+    0xE21938A88F91B4AD  /*  898 */,    0x57DFEFF845C6D3C3  /*  899 */,
+    0x2F006B0BF62CAAF2  /*  900 */,    0x62F479EF6F75EE78  /*  901 */,
+    0x11A55AD41C8916A9  /*  902 */,    0xF229D29084FED453  /*  903 */,
+    0x42F1C27B16B000E6  /*  904 */,    0x2B1F76749823C074  /*  905 */,
+    0x4B76ECA3C2745360  /*  906 */,    0x8C98F463B91691BD  /*  907 */,
+    0x14BCC93CF1ADE66A  /*  908 */,    0x8885213E6D458397  /*  909 */,
+    0x8E177DF0274D4711  /*  910 */,    0xB49B73B5503F2951  /*  911 */,
+    0x10168168C3F96B6B  /*  912 */,    0x0E3D963B63CAB0AE  /*  913 */,
+    0x8DFC4B5655A1DB14  /*  914 */,    0xF789F1356E14DE5C  /*  915 */,
+    0x683E68AF4E51DAC1  /*  916 */,    0xC9A84F9D8D4B0FD9  /*  917 */,
+    0x3691E03F52A0F9D1  /*  918 */,    0x5ED86E46E1878E80  /*  919 */,
+    0x3C711A0E99D07150  /*  920 */,    0x5A0865B20C4E9310  /*  921 */,
+    0x56FBFC1FE4F0682E  /*  922 */,    0xEA8D5DE3105EDF9B  /*  923 */,
+    0x71ABFDB12379187A  /*  924 */,    0x2EB99DE1BEE77B9C  /*  925 */,
+    0x21ECC0EA33CF4523  /*  926 */,    0x59A4D7521805C7A1  /*  927 */,
+    0x3896F5EB56AE7C72  /*  928 */,    0xAA638F3DB18F75DC  /*  929 */,
+    0x9F39358DABE9808E  /*  930 */,    0xB7DEFA91C00B72AC  /*  931 */,
+    0x6B5541FD62492D92  /*  932 */,    0x6DC6DEE8F92E4D5B  /*  933 */,
+    0x353F57ABC4BEEA7E  /*  934 */,    0x735769D6DA5690CE  /*  935 */,
+    0x0A234AA642391484  /*  936 */,    0xF6F9508028F80D9D  /*  937 */,
+    0xB8E319A27AB3F215  /*  938 */,    0x31AD9C1151341A4D  /*  939 */,
+    0x773C22A57BEF5805  /*  940 */,    0x45C7561A07968633  /*  941 */,
+    0xF913DA9E249DBE36  /*  942 */,    0xDA652D9B78A64C68  /*  943 */,
+    0x4C27A97F3BC334EF  /*  944 */,    0x76621220E66B17F4  /*  945 */,
+    0x967743899ACD7D0B  /*  946 */,    0xF3EE5BCAE0ED6782  /*  947 */,
+    0x409F753600C879FC  /*  948 */,    0x06D09A39B5926DB6  /*  949 */,
+    0x6F83AEB0317AC588  /*  950 */,    0x01E6CA4A86381F21  /*  951 */,
+    0x66FF3462D19F3025  /*  952 */,    0x72207C24DDFD3BFB  /*  953 */,
+    0x4AF6B6D3E2ECE2EB  /*  954 */,    0x9C994DBEC7EA08DE  /*  955 */,
+    0x49ACE597B09A8BC4  /*  956 */,    0xB38C4766CF0797BA  /*  957 */,
+    0x131B9373C57C2A75  /*  958 */,    0xB1822CCE61931E58  /*  959 */,
+    0x9D7555B909BA1C0C  /*  960 */,    0x127FAFDD937D11D2  /*  961 */,
+    0x29DA3BADC66D92E4  /*  962 */,    0xA2C1D57154C2ECBC  /*  963 */,
+    0x58C5134D82F6FE24  /*  964 */,    0x1C3AE3515B62274F  /*  965 */,
+    0xE907C82E01CB8126  /*  966 */,    0xF8ED091913E37FCB  /*  967 */,
+    0x3249D8F9C80046C9  /*  968 */,    0x80CF9BEDE388FB63  /*  969 */,
+    0x1881539A116CF19E  /*  970 */,    0x5103F3F76BD52457  /*  971 */,
+    0x15B7E6F5AE47F7A8  /*  972 */,    0xDBD7C6DED47E9CCF  /*  973 */,
+    0x44E55C410228BB1A  /*  974 */,    0xB647D4255EDB4E99  /*  975 */,
+    0x5D11882BB8AAFC30  /*  976 */,    0xF5098BBB29D3212A  /*  977 */,
+    0x8FB5EA14E90296B3  /*  978 */,    0x677B942157DD025A  /*  979 */,
+    0xFB58E7C0A390ACB5  /*  980 */,    0x89D3674C83BD4A01  /*  981 */,
+    0x9E2DA4DF4BF3B93B  /*  982 */,    0xFCC41E328CAB4829  /*  983 */,
+    0x03F38C96BA582C52  /*  984 */,    0xCAD1BDBD7FD85DB2  /*  985 */,
+    0xBBB442C16082AE83  /*  986 */,    0xB95FE86BA5DA9AB0  /*  987 */,
+    0xB22E04673771A93F  /*  988 */,    0x845358C9493152D8  /*  989 */,
+    0xBE2A488697B4541E  /*  990 */,    0x95A2DC2DD38E6966  /*  991 */,
+    0xC02C11AC923C852B  /*  992 */,    0x2388B1990DF2A87B  /*  993 */,
+    0x7C8008FA1B4F37BE  /*  994 */,    0x1F70D0C84D54E503  /*  995 */,
+    0x5490ADEC7ECE57D4  /*  996 */,    0x002B3C27D9063A3A  /*  997 */,
+    0x7EAEA3848030A2BF  /*  998 */,    0xC602326DED2003C0  /*  999 */,
+    0x83A7287D69A94086  /* 1000 */,    0xC57A5FCB30F57A8A  /* 1001 */,
+    0xB56844E479EBE779  /* 1002 */,    0xA373B40F05DCBCE9  /* 1003 */,
+    0xD71A786E88570EE2  /* 1004 */,    0x879CBACDBDE8F6A0  /* 1005 */,
+    0x976AD1BCC164A32F  /* 1006 */,    0xAB21E25E9666D78B  /* 1007 */,
+    0x901063AAE5E5C33C  /* 1008 */,    0x9818B34448698D90  /* 1009 */,
+    0xE36487AE3E1E8ABB  /* 1010 */,    0xAFBDF931893BDCB4  /* 1011 */,
+    0x6345A0DC5FBBD519  /* 1012 */,    0x8628FE269B9465CA  /* 1013 */,
+    0x1E5D01603F9C51EC  /* 1014 */,    0x4DE44006A15049B7  /* 1015 */,
+    0xBF6C70E5F776CBB1  /* 1016 */,    0x411218F2EF552BED  /* 1017 */,
+    0xCB0C0708705A36A3  /* 1018 */,    0xE74D14754F986044  /* 1019 */,
+    0xCD56D9430EA8280E  /* 1020 */,    0xC12591D7535F5065  /* 1021 */,
+    0xC83223F1720AEF96  /* 1022 */,    0xC3A0396F7363A51F  /* 1023 */
+};
Index: /trunk/EraserDll/Eraser.rc
===================================================================
--- /trunk/EraserDll/Eraser.rc	(revision 4)
+++ /trunk/EraserDll/Eraser.rc	(revision 4)
@@ -0,0 +1,379 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// Russian resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_RUS)
+#ifdef _WIN32
+LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT
+#pragma code_page(1251)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO 
+BEGIN
+    IDD_DIALOG_SEC_MAN, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 208
+        TOPMARGIN, 4
+        BOTTOMMARGIN, 86
+    END
+END
+#endif    // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_DIALOG_SEC_MAN DIALOGEX 0, 0, 215, 93
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | 
+    WS_SYSMENU
+CAPTION "Security checking"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+    EDITTEXT        IDC_EDIT_SECMAN_PASSWD,75,21,123,14,ES_PASSWORD | 
+                    ES_AUTOHSCROLL
+    EDITTEXT        IDC_EDIT_SECMAN_PASSWDCONFIRM,75,43,124,14,ES_PASSWORD | 
+                    ES_AUTOHSCROLL | NOT WS_VISIBLE
+    DEFPUSHBUTTON   "OK",IDOK,90,69,50,14
+    PUSHBUTTON      "Cancel",IDCANCEL,148,69,50,14
+    RTEXT           "&Password",IDC_STATIC,26,22,43,8
+    RTEXT           "Confirm password",IDC_STATIC_CONFIRM,11,47,58,8,NOT 
+                    WS_VISIBLE
+    GROUPBOX        "",IDC_STATIC,7,4,201,82
+END
+
+#endif    // Russian resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO 
+BEGIN
+    IDD_PAGE_FILES, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 296
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 167
+    END
+
+    IDD_PAGE_FREESPACE, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 296
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 166
+    END
+
+    IDD_DIALOG_METHODEDIT, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 282
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 235
+    END
+
+    IDD_DIALOG_PASSEDIT, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 181
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 105
+    END
+
+    IDD_DIALOG_REPORT, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 246
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 235
+    END
+END
+#endif    // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_PAGE_FILES DIALOGEX 0, 0, 303, 175
+STYLE DS_SETFONT | WS_CHILD | WS_DISABLED | WS_CAPTION
+CAPTION "Files"
+FONT 8, "MS Sans Serif", 0, 0, 0x1
+BEGIN
+    CONTROL         "List1",IDC_LIST_METHOD,"SysListView32",LVS_REPORT | 
+                    LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | 
+                    WS_TABSTOP,14,20,239,80,WS_EX_STATICEDGE
+    PUSHBUTTON      "&New",IDC_BUTTON_NEW,260,20,37,14
+    PUSHBUTTON      "&Edit",IDC_BUTTON_EDIT,260,37,37,14
+    PUSHBUTTON      "&Delete",IDC_BUTTON_DELETE,260,54,37,14
+    LTEXT           "",IDC_STATIC_SELECTED,14,106,282,8,SS_NOPREFIX
+    LTEXT           "Erase with",IDC_STATIC,7,7,240,8
+    CONTROL         "Cluster Tip Area",IDC_CHECK_FILECLUSTERTIPS,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,14,136,279,10
+    LTEXT           "Overwrite",IDC_STATIC,7,123,286,8
+    CONTROL         "File Names (File Names will always be cleared on NT/XP and above)",
+                    IDC_CHECK_FILENAMES,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,14,146,279,10
+    CONTROL         "Alternate Data Streams",IDC_CHECK_ALTERNATESTREAMS,
+                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,156,279,10
+END
+
+IDD_PAGE_FREESPACE DIALOGEX 0, 0, 303, 175
+STYLE DS_SETFONT | WS_CHILD | WS_DISABLED | WS_CAPTION
+CAPTION "Unused Disk Space"
+FONT 8, "MS Sans Serif", 0, 0, 0x1
+BEGIN
+    CONTROL         "List1",IDC_LIST_METHOD,"SysListView32",LVS_REPORT | 
+                    LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | 
+                    WS_TABSTOP,14,20,239,80,WS_EX_STATICEDGE
+    PUSHBUTTON      "&New",IDC_BUTTON_NEW,260,20,37,14
+    PUSHBUTTON      "&Edit",IDC_BUTTON_EDIT,260,37,37,14
+    PUSHBUTTON      "&Delete",IDC_BUTTON_DELETE,260,54,37,14
+    CONTROL         "Free Disk Space",IDC_CHECK_FREESPACE,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,14,136,279,10
+    CONTROL         "Cluster Tip Area",IDC_CHECK_CLUSTERTIPS,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,14,146,279,10
+    CONTROL         "Directory Entries",IDC_CHECK_DIRECTORYENTRIES,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,14,156,279,10
+    LTEXT           "",IDC_STATIC_SELECTED,14,106,279,8,SS_NOPREFIX
+    LTEXT           "Erase with",IDC_STATIC,7,7,240,8
+    LTEXT           "Overwrite",IDC_STATIC,7,123,286,8
+END
+
+IDD_DIALOG_METHODEDIT DIALOGEX 0, 0, 289, 242
+STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | WS_POPUP | 
+    WS_CAPTION | WS_SYSMENU
+CAPTION "Custom Method Editor"
+FONT 8, "MS Sans Serif", 0, 0, 0x1
+BEGIN
+    EDITTEXT        IDC_EDIT_DESCRIPTION,14,17,268,14,ES_AUTOHSCROLL
+    CONTROL         "List1",IDC_LIST_PASSES,"SysListView32",LVS_REPORT | 
+                    LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | 
+                    WS_TABSTOP,14,53,218,83,WS_EX_STATICEDGE
+    PUSHBUTTON      "&Add",IDC_BUTTON_ADD,237,53,45,14
+    PUSHBUTTON      "&Delete",IDC_BUTTON_DELETE,237,70,45,14
+    PUSHBUTTON      "&Copy",IDC_BUTTON_COPY,237,87,45,14
+    PUSHBUTTON      "Move &Up",IDC_BUTTON_UP,237,104,45,14
+    PUSHBUTTON      "Move Do&wn",IDC_BUTTON_DOWN,237,121,45,14
+    EDITTEXT        IDC_EDIT_BYTE1,26,164,40,14,ES_AUTOHSCROLL
+    CONTROL         "Byte &2",IDC_CHECK_BYTE2,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,76,153,39,10
+    EDITTEXT        IDC_EDIT_BYTE2,76,164,40,14,ES_AUTOHSCROLL
+    CONTROL         "Byte &3",IDC_CHECK_BYTE3,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,126,153,39,10
+    EDITTEXT        IDC_EDIT_BYTE3,126,164,40,14,ES_AUTOHSCROLL
+    CONTROL         "Pseudo&random Data",IDC_RADIO_PSEUDORANDOM,"Button",
+                    BS_AUTORADIOBUTTON,14,183,268,10
+    CONTROL         "&Perform Passes In Random &Order",IDC_CHECK_SHUFFLE,
+                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,210,268,10
+    DEFPUSHBUTTON   "&Save",IDOK,177,222,50,14
+    PUSHBUTTON      "&D&iscard",IDCANCEL,232,222,50,14
+    LTEXT           "Description",IDC_STATIC,7,7,275,8
+    LTEXT           "Overwriting Passes",IDC_STATIC,7,43,275,8
+    CONTROL         "&Pattern",IDC_RADIO_PATTERN,"Button",BS_AUTORADIOBUTTON,
+                    14,142,268,10
+    CONTROL         "",IDC_STATIC,"Static",SS_BLACKFRAME,14,205,268,1
+    LTEXT           "Byte 1",IDC_STATIC_BYTE1,26,153,38,8
+END
+
+IDD_DIALOG_PASSEDIT DIALOG  0, 0, 188, 112
+STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | WS_POPUP | 
+    WS_CAPTION | WS_SYSMENU
+CAPTION "Passes"
+FONT 8, "MS Sans Serif"
+BEGIN
+    DEFPUSHBUTTON   "OK",IDOK,77,91,50,14
+    PUSHBUTTON      "Cancel",IDCANCEL,131,91,50,14
+    LTEXT           "The number of times data should be overwritten before deleting.",
+                    IDC_STATIC,7,7,174,21
+    EDITTEXT        IDC_EDIT_PASSES,68,51,46,14,ES_AUTOHSCROLL | ES_NUMBER
+    CONTROL         "Spin1",IDC_SPIN_PASSES,"msctls_updown32",
+                    UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | 
+                    UDS_ARROWKEYS | UDS_NOTHOUSANDS,113,51,7,14
+    LTEXT           "Passes:",IDC_STATIC,68,42,26,8
+END
+
+IDD_DIALOG_REPORT DIALOG  0, 0, 253, 242
+STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | WS_POPUP | WS_VISIBLE | 
+    WS_CAPTION | WS_SYSMENU
+CAPTION "Erasing Report"
+FONT 8, "MS Sans Serif"
+BEGIN
+    DEFPUSHBUTTON   "&Close",IDCANCEL,196,221,50,14
+    PUSHBUTTON      "&Save As...",IDC_BUTTON_SAVEAS,140,221,50,14
+    EDITTEXT        IDC_EDIT_STATISTICS,7,42,239,80,ES_MULTILINE | 
+                    ES_READONLY | WS_VSCROLL | WS_HSCROLL
+    CONTROL         "List1",IDC_LIST_ERRORS,"SysListView32",LVS_REPORT | 
+                    LVS_SINGLESEL | WS_BORDER | WS_TABSTOP,7,144,239,69
+    CONTROL         "",IDC_STATIC,"Static",SS_ETCHEDHORZ,7,22,239,1
+    LTEXT           "Task completed.",IDC_STATIC_COMPLETION,7,7,239,14
+    LTEXT           "Information:",IDC_STATIC,7,30,38,8
+    LTEXT           "Failures:",IDC_STATIC_FAILURES_HEADER,7,132,239,8
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDR_MAINFRAME           ICON                    "res\\Eraser.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE 
+BEGIN
+    IDS_PROPSHT_CAPTION     "Preferences: Erasing"
+    IDS_PASSWDNOTMATCH      "Password does not match"
+END
+
+STRINGTABLE 
+BEGIN
+    IDS_ERROR_CLUSTER       "Failed to determine cluster size from drive %1. Cluster tip area will not be erased."
+    IDS_ERROR_MEMORY        "Failed to allocate data buffer (out of memory). Try closing other applications or restarting Windows."
+    IDS_ERROR_INTERNAL      "Internal error, something way unexpected just happened."
+    IDS_ERROR_DIRECTORY     "Failed to create temporary directory to drive %1, maybe one exists already. Try again."
+    IDS_ERROR_FREESPACE     "Failed to determine free space available on drive %1. Free disk space (or at least some of it) could not be erased."
+    IDS_ERROR_DIRENTRIES    "Failed to erase file names from drive %1, don't know why exactly."
+    IDS_ERROR_DIRENTRIES_FS "Failed to erase file names from drive %1, this file system type is not supported."
+    IDS_ERROR_DIRENTRIES_FAT 
+                            "Failed to clean directory entries from drive %1, there was something not quite right with the file system. You may want to run ScanDisk."
+    IDS_ERROR_DIRENTRIES_MAXRESTARTS 
+                            "Failed to clean directory entries from drive %1, gave up after several attempts. You may want to try closing other applications and see if that helps."
+    IDS_ERROR_NODATA        "There was nothing to erase."
+    IDS_ERROR_DIRECTORY_REMOVE 
+                            "Failed to remove a temporary directory from drive %1, you may want to remove it manually to recover (possibly) lost disk space."
+    IDS_ERROR_DIRENTRIES_LOCK 
+                            "Failed to clean directory entry %1, could not prevent other programs from touching it."
+    IDS_ERROR_TEMPFILE      "Failed to create a temporary file or directory. Erasing was not completed."
+    IDS_ERROR_ADS           "Failed to erase all (alternate) data streams from file %1, it had more than one."
+END
+
+STRINGTABLE 
+BEGIN
+    IDS_METHOD_DELETE       "Are you sure you want to delete the selected method?"
+    IDS_METHOD_NOPASSES     "Method contains no overwriting passes. Do you want to discard the changes?"
+END
+
+STRINGTABLE 
+BEGIN
+    AFX_IDS_APP_TITLE       "Eraser"
+END
+
+#endif    // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Finnish resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_FIN)
+#ifdef _WIN32
+LANGUAGE LANG_FINNISH, SUBLANG_DEFAULT
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE 
+BEGIN
+    "resource.h\0"
+END
+
+2 TEXTINCLUDE 
+BEGIN
+    "#include ""afxres.h""\r\n"
+    "\0"
+END
+
+3 TEXTINCLUDE 
+BEGIN
+    "#define _AFX_NO_SPLITTER_RESOURCES\r\n"
+    "#define _AFX_NO_OLE_RESOURCES\r\n"
+    "#define _AFX_NO_TRACKER_RESOURCES\r\n"
+    "#define _AFX_NO_PROPERTY_RESOURCES\r\n"
+    "\r\n"
+    "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n"
+    "#ifdef _WIN32\r\n"
+    "LANGUAGE 9, 1\r\n"
+    "#pragma code_page(1252)\r\n"
+    "#endif\r\n"
+    "#include ""res\\Eraser.rc2""  // non-Microsoft Visual C++ edited resources\r\n"
+    "#include ""afxres.rc""         // Standard components\r\n"
+    "#endif\0"
+END
+
+#endif    // APSTUDIO_INVOKED
+
+#endif    // Finnish resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+#define _AFX_NO_SPLITTER_RESOURCES
+#define _AFX_NO_OLE_RESOURCES
+#define _AFX_NO_TRACKER_RESOURCES
+#define _AFX_NO_PROPERTY_RESOURCES
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE 9, 1
+#pragma code_page(1252)
+#endif
+#include "res\Eraser.rc2"  // non-Microsoft Visual C++ edited resources
+#include "afxres.rc"         // Standard components
+#endif
+/////////////////////////////////////////////////////////////////////////////
+#endif    // not APSTUDIO_INVOKED
+
Index: /trunk/EraserDll/SecurityManager.h
===================================================================
--- /trunk/EraserDll/SecurityManager.h	(revision 4)
+++ /trunk/EraserDll/SecurityManager.h	(revision 4)
@@ -0,0 +1,38 @@
+// SecurityManager.h
+//
+// Eraser. Secure data removal. For Windows.
+// Copyright © 1997-2001  Sami Tolvanen (sami@tolvanen.com).
+// Copyright © 2001-2006  Garrett Trant (support@heidi.ie).
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+#pragma once
+#include "EraserDll.h"
+
+class ERASER_API CSecurityManager
+{
+	CSecurityManager(void);
+	~CSecurityManager(void);
+public:
+
+	static void Protect(const char* szSecret );
+	static void Unprotect();
+	static bool Check(const char* szSecret );
+	static bool IsProtected();
+};
+
+bool ERASER_API CheckAccess(DWORD dwMaxError = 3);
+bool ERASER_API SetProtection();
+bool ERASER_API ClearProtection();
Index: /trunk/EraserDll/PassEditDlg.h
===================================================================
--- /trunk/EraserDll/PassEditDlg.h	(revision 4)
+++ /trunk/EraserDll/PassEditDlg.h	(revision 4)
@@ -0,0 +1,67 @@
+// PassEditDlg.h
+//
+// Eraser. Secure data removal. For Windows.
+// Copyright © 1997-2001  Sami Tolvanen (sami@tolvanen.com).
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#if !defined(AFX_PASSEDITDLG_H__007F8270_BFB9_11D3_82A0_000000000000__INCLUDED_)
+#define AFX_PASSEDITDLG_H__007F8270_BFB9_11D3_82A0_000000000000__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+/////////////////////////////////////////////////////////////////////////////
+// CPassEditDlg dialog
+
+class ERASER_API CPassEditDlg : public CDialog
+{
+// Construction
+public:
+    CPassEditDlg(CWnd* pParent = NULL);   // standard constructor
+
+// Dialog Data
+    //{{AFX_DATA(CPassEditDlg)
+    enum { IDD = IDD_DIALOG_PASSEDIT };
+    CSpinButtonCtrl m_spinPasses;
+    DWORD    m_uPasses;
+    //}}AFX_DATA
+
+
+// Overrides
+    // ClassWizard generated virtual function overrides
+    //{{AFX_VIRTUAL(CPassEditDlg)
+    protected:
+    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
+    //}}AFX_VIRTUAL
+
+// Implementation
+protected:
+    bool m_bIgnoreChange;
+
+    // Generated message map functions
+    //{{AFX_MSG(CPassEditDlg)
+    virtual BOOL OnInitDialog();
+	afx_msg void OnChangeEditPasses();
+	//}}AFX_MSG
+    DECLARE_MESSAGE_MAP()
+};
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_PASSEDITDLG_H__007F8270_BFB9_11D3_82A0_000000000000__INCLUDED_)
Index: /trunk/EraserDll/ByteEdit.cpp
===================================================================
--- /trunk/EraserDll/ByteEdit.cpp	(revision 4)
+++ /trunk/EraserDll/ByteEdit.cpp	(revision 4)
@@ -0,0 +1,129 @@
+// ByteEdit.cpp
+//
+// Eraser. Secure data removal. For Windows.
+// Copyright © 1997-2001  Sami Tolvanen (sami@tolvanen.com).
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#include "stdafx.h"
+#include "eraser.h"
+#include "ByteEdit.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CByteEdit
+
+CByteEdit::CByteEdit()
+{
+}
+
+CByteEdit::~CByteEdit()
+{
+}
+
+
+BEGIN_MESSAGE_MAP(CByteEdit, CEdit)
+    //{{AFX_MSG_MAP(CByteEdit)
+    ON_WM_CHAR()
+    ON_WM_KEYDOWN()
+    ON_WM_RBUTTONDOWN()
+    //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CByteEdit message handlers
+
+void CByteEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
+{
+    if (nChar == TEXT('0') || nChar == TEXT('1'))
+    {
+        CString strText;
+        int     startPos;
+        int     endPos;
+
+        GetSel(startPos, endPos);
+        GetWindowText(strText);
+
+        if (startPos >= 0 && startPos < 8)
+        {
+            strText.SetAt(startPos, (TCHAR)nChar);
+            SetWindowText((LPCTSTR)strText);
+            SetSel(startPos + 1, startPos + 1);
+        }
+    }
+    else if (nChar == VK_LEFT || nChar == VK_RIGHT)
+        CEdit::OnChar(nChar, nRepCnt, nFlags);
+    else
+        MessageBeep(MB_ICONASTERISK);
+}
+
+BYTE CByteEdit::GetByte()
+{
+    BYTE    byte = 0;
+    CString str;
+
+    GetWindowText(str);
+
+    for (BYTE i = 0; i < 8; i++)
+    {
+        if (str[(int)i] == TEXT('1'))
+            byte |= (1 << (7 - i));
+    }
+
+    return byte;
+}
+
+void CByteEdit::SetByte(BYTE byte)
+{
+    CString str = TEXT("00000000");
+
+    for (BYTE i = 0; i < 8; i++)
+        str.SetAt(7 - i, (byte & (1 << i)) ? TEXT('1') : TEXT('0'));
+
+    SetWindowText(str);
+}
+
+BOOL CByteEdit::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext)
+{
+    if (CWnd::Create(lpszClassName, lpszWindowName, dwStyle, rect, pParentWnd, nID, pContext))
+    {
+        SetLimitText(8);
+        SetByte(0);
+
+        return TRUE;
+    }
+
+    return FALSE;
+}
+
+void CByteEdit::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
+{
+    if (IsCharAlphaNumeric((TCHAR)nChar) || nChar == VK_LEFT ||
+        nChar == VK_RIGHT || nChar == VK_HOME || nChar == VK_END)
+    {
+        CEdit::OnKeyDown(nChar, nRepCnt, nFlags);
+    }
+}
+
+void CByteEdit::OnRButtonDown(UINT /*nFlags*/, CPoint /*point*/)
+{
+    return;
+}
Index: /trunk/EraserDll/Gutmann.cpp
===================================================================
--- /trunk/EraserDll/Gutmann.cpp	(revision 4)
+++ /trunk/EraserDll/Gutmann.cpp	(revision 4)
@@ -0,0 +1,124 @@
+// Gutmann.cpp
+//
+// Implements file erasing method described in Secure Deletion of Data from
+// Magnetic and Solid-State Memory by Peter Gutmann (USENIX, 1996).
+//
+// Eraser. Secure data removal. For Windows.
+// Copyright © 1997-2001  Sami Tolvanen (sami@tolvanen.com).
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#include "stdafx.h"
+#include "EraserDll.h"
+#include "Common.h"
+#include "Gutmann.h"
+
+bool
+wipeFileWithGutmann(CEraserContext *context)
+{
+    LPPASS   passGutmann = context->m_lpmMethod->m_lpPasses;
+    E_UINT32 uStartTime = GetTickCount();
+    E_UINT32 uUsedSize  = 0;
+    E_UINT32 uSavedSize = 0;
+    E_UINT64 uLength    = 0;
+    E_UINT64 uWiped     = 0;
+    E_UINT32 uWritten   = 0;
+    bool     bCompleted = true;
+
+    // send the begin message only once
+    postStartNotification(context);
+
+    setBufferSize(context, uSavedSize);
+
+    // shuffle the pass array, except for the random passes
+    shufflePassArray((LPPASS)(passGutmann + PASSES_GUTMANN_RANDOM),
+                     (PASSES_GUTMANN - 2 * PASSES_GUTMANN_RANDOM));
+
+    for (E_UINT16 uCurrentPass = 0; uCurrentPass < PASSES_GUTMANN; uCurrentPass++) {
+        eraserSafeAssign(context, context->m_uProgressCurrentPass, (E_UINT16)(uCurrentPass + 1));
+
+        // start from the beginning again
+        SetFilePointer(context->m_hFile, context->m_uiFileStart.LowPart,
+                       (E_PINT32)&context->m_uiFileStart.HighPart, FILE_BEGIN);
+
+        uLength = context->m_uiFileSize.QuadPart;
+        uUsedSize = uSavedSize;
+
+        // fill buffer
+        fillPassData(context->m_puBuffer, uUsedSize, &passGutmann[uCurrentPass]);
+
+        while (uLength > 0) {
+            // random data needs refilling
+            if (isRandomPass(passGutmann[uCurrentPass])) {
+                isaacFill((E_PUINT8)context->m_puBuffer, uUsedSize);
+            }
+
+            // use the whole buffer as long as we can
+            if (uLength < (E_UINT64)uUsedSize) {
+                uUsedSize = (E_UINT32)uLength;
+            }
+
+            // completed if not terminated and write is successful
+            bCompleted = !eraserInternalTerminated(context) &&
+                         WriteFile(context->m_hFile, context->m_puBuffer,
+                                   uUsedSize, &uWritten, NULL) &&
+                         (uUsedSize == uWritten);
+
+            // flush to disk
+            FlushFileBuffers(context->m_hFile);
+
+            // if not completed - stop!
+            if (!bCompleted) {
+                break;
+            }
+
+            // set statistics
+            context->m_uProgressWiped += (E_UINT64)uUsedSize;
+            uWiped += (E_UINT64)uUsedSize;
+
+            // how much left to go?
+            uLength -= (E_UINT64)uUsedSize;
+
+            // send update to window
+            postUpdateNotification(context, PASSES_GUTMANN);
+        }
+
+        if (context->m_uTestMode && !eraserInternalTerminated(context)) {
+            // pause, so the results can be examined
+            context->m_evTestContinue.ResetEvent();
+            eraserTestPausedNotify(context);
+            WaitForSingleObject(context->m_evTestContinue, INFINITE);
+        }
+
+        if (!bCompleted) {
+            break;
+        }
+    }
+
+    // set statistics
+    setEndStatistics(context, uWiped, uStartTime);
+
+    // the pass array could reveal the order of overwriting passes to a
+    // possible intruder. we cannot zero the array, but we can shuffle
+    // it again after the operation. so is this really necessary? I don't
+    // know, but one can never be too careful, right?
+
+    // shuffle the pass array again to remove traces of pass order
+    shufflePassArray((LPPASS)(passGutmann + PASSES_GUTMANN_RANDOM),
+                     (PASSES_GUTMANN - 2 * PASSES_GUTMANN_RANDOM));
+
+    return bCompleted;
+}
Index: /trunk/EraserDll/Custom.cpp
===================================================================
--- /trunk/EraserDll/Custom.cpp	(revision 4)
+++ /trunk/EraserDll/Custom.cpp	(revision 4)
@@ -0,0 +1,130 @@
+// Custom.cpp
+//
+// Generic wipe function.
+//
+// Eraser. Secure data removal. For Windows.
+// Copyright © 1997-2001  Sami Tolvanen (sami@tolvanen.com).
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#include "stdafx.h"
+#include "EraserDll.h"
+#include "Common.h"
+#include "Custom.h"
+
+bool
+wipeFileWithCustom(CEraserContext *context)
+{
+    if (!AfxIsValidAddress(context->m_lpmMethod, sizeof(METHOD)) ||
+        !AfxIsValidAddress(context->m_lpmMethod->m_lpPasses,
+                           sizeof(PASS) * context->m_lpmMethod->m_nPasses)) {
+        return false;
+    }
+
+    E_UINT32 uStartTime = GetTickCount();
+    E_UINT32 uUsedSize  = 0;
+    E_UINT32 uSavedSize = 0;
+    E_UINT64 uLength    = 0;
+    E_UINT64 uWiped     = 0;
+    E_UINT32 uWritten   = 0;
+    bool     bCompleted = true;
+
+    // send the begin message only once
+    postStartNotification(context);
+
+    setBufferSize(context, uSavedSize);
+
+    // shuffle the pass array
+    if (context->m_lpmMethod->m_bShuffle) {
+        shufflePassArray((LPPASS)context->m_lpmMethod->m_lpPasses,
+                         context->m_lpmMethod->m_nPasses);
+    }
+
+    for (E_UINT16 uCurrentPass = 0;
+         uCurrentPass < context->m_lpmMethod->m_nPasses; uCurrentPass++) {
+        eraserSafeAssign(context, context->m_uProgressCurrentPass,
+                         (E_UINT16)(uCurrentPass + 1));
+
+        // start from the beginning again
+        SetFilePointer(context->m_hFile, context->m_uiFileStart.LowPart,
+                       (E_PINT32)&context->m_uiFileStart.HighPart, FILE_BEGIN);
+
+        uLength = context->m_uiFileSize.QuadPart;
+        uUsedSize = uSavedSize;
+
+        // fill buffer
+        fillPassData(context->m_puBuffer, uUsedSize,
+                     &context->m_lpmMethod->m_lpPasses[uCurrentPass]);
+
+        while (uLength > 0) {
+            // random data needs refilling
+            if (isRandomPass(context->m_lpmMethod->m_lpPasses[uCurrentPass])) {
+                isaacFill((E_PUINT8)context->m_puBuffer, uUsedSize);
+            }
+
+            // use the whole buffer as long as we can
+            if (uLength < (E_UINT64)uUsedSize) {
+                uUsedSize = (E_UINT32)uLength;
+            }
+
+            // completed if not terminated and write is successful
+            bCompleted = !eraserInternalTerminated(context) &&
+                         WriteFile(context->m_hFile, context->m_puBuffer,
+                                   uUsedSize, &uWritten, NULL) &&
+                         (uUsedSize == uWritten);
+
+            // flush to disk
+            FlushFileBuffers(context->m_hFile);
+
+            // if not completed - stop!
+            if (!bCompleted) {
+                break;
+            }
+
+            // set statistics
+            context->m_uProgressWiped += (E_UINT64)uUsedSize;
+            uWiped += (E_UINT64)uUsedSize;
+
+            // how much left to go?
+            uLength -= (E_UINT64)uUsedSize;
+
+            // send update to window
+            postUpdateNotification(context, context->m_lpmMethod->m_nPasses);
+        }
+
+        if (context->m_uTestMode && !eraserInternalTerminated(context)) {
+            // pause, so the results can be examined
+            context->m_evTestContinue.ResetEvent();
+            eraserTestPausedNotify(context);
+            WaitForSingleObject(context->m_evTestContinue, INFINITE);
+        }
+
+        if (!bCompleted) {
+            break;
+        }
+    }
+
+    // set statistics
+    setEndStatistics(context, uWiped, uStartTime);
+
+    // shuffle the pass array again to remove traces of pass order
+    if (context->m_lpmMethod->m_bShuffle) {
+        shufflePassArray((LPPASS)context->m_lpmMethod->m_lpPasses,
+                         context->m_lpmMethod->m_nPasses);
+    }
+
+    return bCompleted;
+}
Index: /trunk/EraserDll/FirstLast2kb.cpp
===================================================================
--- /trunk/EraserDll/FirstLast2kb.cpp	(revision 4)
+++ /trunk/EraserDll/FirstLast2kb.cpp	(revision 4)
@@ -0,0 +1,106 @@
+
+#include "stdafx.h"
+#include "EraserDll.h"
+#include "Common.h"
+#include "FirstLast2kb.h"
+#include "RND.h"
+
+#define OFFSET_FL2K 2048
+
+bool wipeFileWithFirstLast2kb(CEraserContext *context) 
+{ 
+   DWORD highPart; 
+   DWORD lowPart(GetFileSize(context->m_hFile, &highPart)); 
+
+   //Also check the HighPart here 
+   bool first_only = lowPart < OFFSET_FL2K && highPart == 0; 
+   context->m_uiFileSize.LowPart = /*first_only ? lowPart :*/ OFFSET_FL2K; 
+   //Make sure HighPart is reset to 0 when wiping the 1st OFFSET_FL2K bytes 
+   context->m_uiFileSize.HighPart = 0; 
+   memset(&context->m_uiFileStart,0, sizeof(context->m_uiFileStart)); 
+   if (!wipeFileWithPseudoRandom(context)) 
+      return false; 
+
+   if(first_only) 
+      return true; 
+
+   //context->m_uiFileSize.LowPart = OFFSET_FL2K; 
+   //context->m_uiFileStart.LowPart = lowPart - OFFSET_FL2K; 
+   //context->m_uiFileStart.HighPart = highPart; 
+
+   context->m_uiFileStart.LowPart = lowPart; 
+   context->m_uiFileStart.HighPart = highPart; 
+   context->m_uiFileStart.QuadPart -= OFFSET_FL2K; 
+
+   //Get the block size for this drive - From function fileSizeToArea() in "EraserDllInternal.h" 
+   E_UINT64 uBlockSize = max(context->m_piCurrent.m_uCluster, 
+         max(context->m_piCurrent.m_uSector, DEFAULT_SECTOR_SIZE)); 
+
+   //Convert m_uiFileStart (ActualFileSize - OFFSET_FL2K) to an exact multiple "of the volume's sector size." 
+   //This value will be >= m_uiFileStart 
+   E_UINT64 uTotal = fileSizeToArea(context, context->m_uiFileStart.QuadPart); 
+
+   //Now, since uTotal > (ActualFileSize - OFFSET_FL2K), we need to backup the starting position by 1 uBlockSize 
+      //to make sure that the last OFFSET_FL2K bytes of the file are actually overwritten 
+   context->m_uiFileStart.QuadPart = uTotal - uBlockSize; 
+
+   //Reset m_uiFileSize to the actual filesize 
+   context->m_uiFileSize.LowPart = lowPart; 
+   context->m_uiFileSize.HighPart = highPart; 
+
+   //Convert m_uiFileSize to an exact multiple "of the volume's sector size" so that the slack space 
+      //at the end gets filled 
+   context->m_uiFileSize.QuadPart = fileSizeToArea(context, context->m_uiFileSize.QuadPart); 
+
+   //Convert m_uiFileSize to the amount of bytes we want to overwrite. 
+   //This is equal to FileSizeOnDisk - m_uiFileStart 
+   //This is also an exact multiple "of the volume's sector size" because with "FILE_FLAG_NO_BUFFERING" 
+      //WriteFile has to write in multiples 
+   context->m_uiFileSize.QuadPart -= context->m_uiFileStart.QuadPart; 
+
+   return wipeFileWithPseudoRandom(context); 
+} 
+
+bool oldwipeFileWithFirstLast2kb(CEraserContext *context)
+{
+
+	struct CtxGuard
+	{
+		CEraserContext *ctx_;
+		ULARGE_INTEGER m_uiFileSize;
+		ULARGE_INTEGER m_uiFileStart;
+		CtxGuard(CEraserContext *ctx)
+			:ctx_(ctx)
+		{
+			memcpy(&m_uiFileSize, &ctx->m_uiFileSize, sizeof(m_uiFileSize));
+			memcpy(&m_uiFileStart, &ctx->m_uiFileStart, sizeof(m_uiFileStart));
+		}
+
+		~CtxGuard()
+		{
+			memcpy(&ctx_->m_uiFileSize, &m_uiFileSize, sizeof(m_uiFileSize));
+			memcpy(&ctx_->m_uiFileStart, &m_uiFileStart, sizeof(m_uiFileStart));
+
+		}
+	};
+
+	if (context->m_uiFileSize.QuadPart <= OFFSET_FL2K )
+	{
+		return wipeFileWithPseudoRandom(context);
+	}
+
+	CtxGuard guard(context);
+	
+	context->m_uiFileSize.QuadPart = OFFSET_FL2K;
+	
+	
+	if (!wipeFileWithPseudoRandom(context))
+		return false;
+	
+
+	//context->m_uiFileSize.QuadPart = guard.m_uiFileSize.QuadPart;
+	context->m_uiFileStart.QuadPart = guard.m_uiFileSize.QuadPart - OFFSET_FL2K;	
+
+	return wipeFileWithPseudoRandom(context);
+
+}
Index: /trunk/EraserDll/Pass.h
===================================================================
--- /trunk/EraserDll/Pass.h	(revision 4)
+++ /trunk/EraserDll/Pass.h	(revision 4)
@@ -0,0 +1,239 @@
+// Pass.h
+// Tools for handling overwriting passes and pass shuffling
+//
+// Eraser. Secure data removal. For Windows.
+// Copyright © 1997-2001  Sami Tolvanen (sami@tolvanen.com).
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#ifndef PASS_H
+#define PASS_H
+#ifdef DMARS
+#define WIPEFUNCTION bool
+#endif
+#include "Random.h"
+#include "FillMemoryWith.h"
+
+///////////////////////////////////////////////////////////////////////////////
+// definitions
+
+// method IDs
+#define BUILTIN_METHOD_ID       0x80
+#define CUSTOM_METHOD_ID        0x00
+
+#define MAX_CUSTOM_METHODS      (BUILTIN_METHOD_ID - 1)
+#define MAX_CUSTOM_METHOD_ID    (MAX_CUSTOM_METHODS | CUSTOM_METHOD_ID)
+
+#define MAX_BUILTIN_METHODS     MAX_CUSTOM_METHODS
+#define MAX_BUILTIN_METHOD_ID   (MAX_BUILTIN_METHODS | BUILTIN_METHOD_ID)
+
+// special data
+#define RND_DATA                ((E_UINT16)-1)
+#define RND_CHAR                (RND_DATA - 1)
+
+// pass definitions
+#define passThree(x, y, z)      { 3, (x), (y), (z) }
+#define passTwo(x, y)           { 2, (x), (y),  0  }
+#define passOne(x)              { 1, (x),  0,   0  }
+#define passRandom              passOne(RND_DATA)
+
+#define setPassThree(pass, x, y, z) \
+    { (pass).bytes = 3; (pass).byte1 = (x); (pass).byte2 = (y); (pass).byte3 = (z); }
+#define setPassTwo(pass, x, y) \
+    { (pass).bytes = 2; (pass).byte1 = (x); (pass).byte2 = (y); (pass).byte3 = 0; }
+#define setPassOne(pass, x) \
+    { (pass).bytes = 1; (pass).byte1 = (x); (pass).byte2 = (pass).byte3 = 0; }
+#define setPassRandom(pass, x) \
+    setPassOne(pass, RND_DATA)
+
+#define isRandomPass(pass) \
+    ((pass).byte1 == RND_DATA)
+
+///////////////////////////////////////////////////////////////////////////////
+// structures
+
+#pragma pack(1)
+
+// pass structure - we'll settle for at most three adjacent bytes
+typedef struct _ThreeBytePass {
+    E_UINT8  bytes;                  // number of bytes used
+    E_UINT16 byte1;
+    E_UINT16 byte2;
+    E_UINT16 byte3;
+} PASS, *LPPASS;
+
+#define DESCRIPTION_SIZE    (80+1)
+
+typedef class _MethodBase {
+public:
+    E_UINT8      m_nMethodID;                        // ID
+    TCHAR        m_szDescription[DESCRIPTION_SIZE];  // description
+    E_UINT16     m_nPasses;                          // number of PASSes
+    WIPEFUNCTION m_pwfFunction;                      // the wipe function
+
+    E_UINT8      m_bShuffle;                         // shuffle passes
+    LPPASS       m_lpPasses;                         // pointer to PASSes
+} BMETHOD, *LPBMETHOD;
+
+#pragma pack()
+
+#define bmEntry(a, b, c, d, e, f)   { a, b, c, d, e, (LPPASS)f }
+
+// method definition - everything needed to save pass data
+typedef class _Method : public _MethodBase {
+public:
+    _Method() {
+        ZeroMemory(this, sizeof(_Method));
+    }
+
+    ~_Method() {
+        if (m_lpPasses) {
+            try {
+                if (m_nPasses > 0) {
+                    ZeroMemory(m_lpPasses, m_nPasses * sizeof(PASS));
+                }
+                delete[] m_lpPasses;
+                m_lpPasses = 0;
+            } catch (...) {
+                ASSERT(0);
+            }
+        }
+        ZeroMemory(this, sizeof(_Method));
+    }
+
+    _Method& operator=(const _MethodBase& rs) {
+        return copy(*(const _Method*)&rs); // way ugly
+    }
+
+    _Method& operator=(const _Method& rs) {
+        return copy(rs);
+    }
+	/*void Serialize(CArchive& ar)
+	{
+		int i=0;
+		if (ar.IsStoring())
+		{
+			ar << (BYTE)m_nMethodID;
+			for (i=0; i<DESCRIPTION_SIZE; i++)	ar << (char)m_szDescription[i];
+			ar << (WORD)m_nPasses;
+			
+			ar << (BYTE)m_bShuffle;
+			for (i=0; i<m_nPasses; i++)
+			{
+                ar << (BYTE)m_lpPasses[i].bytes;
+				ar << (WORD)m_lpPasses[i].byte1;
+				ar << (WORD)m_lpPasses[i].byte2;
+				ar << (WORD)m_lpPasses[i].byte3;
+			}
+		}
+		else
+		{			
+			ar >> (BYTE)m_nMethodID;
+			for (i=0; i<DESCRIPTION_SIZE; i++)	ar >> (char)m_szDescription[i];
+			ar >> (WORD)m_nPasses;
+			
+			ar >> (BYTE)m_bShuffle;
+			m_lpPasses = new PASS[m_nPasses];
+			for (i=0; i<m_nPasses; i++)
+			{
+				ar >> (BYTE)m_lpPasses[i].bytes;
+				ar >> (WORD)m_lpPasses[i].byte1;
+				ar >> (WORD)m_lpPasses[i].byte2;
+				ar >> (WORD)m_lpPasses[i].byte3;
+			}
+			//m_pwfFunction = 0;
+		}
+	}*/
+
+private:
+    _Method& copy(const _Method& rs) {
+        if (this != &rs) {
+            try {
+                if (m_lpPasses) {
+                    if (m_nPasses > 0) {
+                        ZeroMemory(m_lpPasses, m_nPasses * sizeof(PASS));
+                    }
+                    delete[] m_lpPasses;
+                    m_lpPasses = 0;
+                    m_nPasses = 0;
+                }
+
+                m_nMethodID = rs.m_nMethodID;
+                lstrcpyn(m_szDescription, rs.m_szDescription, DESCRIPTION_SIZE);
+
+                m_nPasses = rs.m_nPasses;
+                m_pwfFunction = rs.m_pwfFunction;
+
+                if (rs.m_lpPasses && rs.m_nPasses > 0) {
+                    m_lpPasses = new PASS[rs.m_nPasses];
+                    for (E_UINT16 i = 0; i < rs.m_nPasses; i++) {
+                        m_lpPasses[i] = rs.m_lpPasses[i];
+                    }
+                }
+
+                m_bShuffle = rs.m_bShuffle;
+            } catch (...) {
+                ASSERT(0);
+            }
+        }
+        return *this;
+    }
+} METHOD, *LPMETHOD;
+
+ERASER_API const BMETHOD*  GetBMethods() ;
+///////////////////////////////////////////////////////////////////////////////
+// built-in methods
+
+const E_UINT8 nBuiltinMethods       = 6;
+
+// maximum number of passes allowed
+#define PASSES_MAX                  ((E_UINT16)-1)
+
+#define GUTMANN_METHOD_ID           ((1 << 0) | BUILTIN_METHOD_ID)
+#define PASSES_GUTMANN              35
+#define PASSES_GUTMANN_RANDOM       4
+
+#define DOD_METHOD_ID               ((1 << 1) | BUILTIN_METHOD_ID)
+#define PASSES_DOD                  7
+
+#define DOD_E_METHOD_ID             ((1 << 2) | BUILTIN_METHOD_ID)
+#define PASSES_DOD_E                3
+
+#define RANDOM_METHOD_ID            ((1 << 3) | BUILTIN_METHOD_ID)
+#define PASSES_RND                  1
+#define PASSES_RND_MAX              PASSES_MAX
+
+#define FL2KB_METHOD_ID            ((1 << 4) | BUILTIN_METHOD_ID)
+#define PASSES_FL2KB                  1
+#define PASSES_FL2KB_MAX              2
+
+#define SCHNEIER_METHOD_ID            ((1 << 5) | BUILTIN_METHOD_ID)
+#define PASSES_SCHNEIER                  7
+#define PASSES_SCHNEIER_MAX              7
+
+// default for files
+#define DEFAULT_FILE_METHOD_ID      GUTMANN_METHOD_ID
+#define DEFAULT_FILE_PASSES         PASSES_GUTMANN
+// default for unused disk space
+#define DEFAULT_UDS_METHOD_ID       RANDOM_METHOD_ID
+#define DEFAULT_UDS_PASSES          PASSES_RND
+
+// global array of built-in methods
+#ifndef PASS_CPP
+extern const BMETHOD bmMethods[nBuiltinMethods];
+#endif
+
+#endif // PASS_H
Index: /trunk/EraserDll/DOD.h
===================================================================
--- /trunk/EraserDll/DOD.h	(revision 4)
+++ /trunk/EraserDll/DOD.h	(revision 4)
@@ -0,0 +1,27 @@
+// DOD.h
+//
+// Eraser. Secure data removal. For Windows.
+// Copyright © 1997-2001  Sami Tolvanen (sami@tolvanen.com).
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#ifndef DOD_H
+#define DOD_H
+
+bool
+wipeFileWithDoD(CEraserContext *context);
+
+#endif // DOD_H
Index: /trunk/EraserDll/Schneier7Pass.cpp
===================================================================
--- /trunk/EraserDll/Schneier7Pass.cpp	(revision 4)
+++ /trunk/EraserDll/Schneier7Pass.cpp	(revision 4)
@@ -0,0 +1,113 @@
+#include "stdafx.h"
+#include "Schneier7pass.h"
+#include "EraserDll.h"
+#include "Common.h"
+enum
+{
+	SCHNEIER_PASS_COUNT = 7
+};
+typedef bool (*PFPassFillStrategy)(E_PUINT8, E_UINT32);
+static bool oneFill(E_PUINT8 pBuffer, E_UINT32 bufferSize)
+{
+	memset(pBuffer, 1, bufferSize);
+	return true;
+}
+static bool zeroFill(E_PUINT8 pBuffer, E_UINT32 bufferSize)
+{
+	memset(pBuffer, 0, bufferSize);
+	return true;
+}
+static PFPassFillStrategy sPassStrategy[SCHNEIER_PASS_COUNT ] =
+{
+	oneFill,
+	zeroFill,
+	isaacFill,
+	isaacFill,
+	isaacFill,
+	isaacFill,
+	isaacFill	
+};
+
+bool wipeFileWithSchneier7Pass(CEraserContext *context)
+{
+	E_UINT32 uStartTime = GetTickCount();
+	E_UINT32 uUsedSize  = 0;
+	E_UINT32 uSavedSize = 0;
+	E_UINT64 uLength    = 0;
+	E_UINT64 uWiped     = 0;
+	E_UINT32 uWritten   = 0;
+	bool     bCompleted = true;
+
+	// send the begin message only once
+	postStartNotification(context);
+
+	setBufferSize(context, uSavedSize);
+
+	for (E_UINT16 uCurrentPass = 0; uCurrentPass < SCHNEIER_PASS_COUNT; uCurrentPass++) 
+	{
+		eraserSafeAssign(context, context->m_uProgressCurrentPass, (E_UINT16)(uCurrentPass + 1));
+
+		// start from the beginning again
+		SetFilePointer(context->m_hFile, context->m_uiFileStart.LowPart,
+			(E_PINT32)&context->m_uiFileStart.HighPart, FILE_BEGIN);
+
+		uLength = context->m_uiFileSize.QuadPart;
+		uUsedSize = uSavedSize;
+
+		while (uLength > 0) 
+		{			
+			sPassStrategy[uCurrentPass]((E_PUINT8)context->m_puBuffer, uUsedSize);
+
+			// use the whole buffer as long as we can
+			if (uLength < (E_UINT64)uUsedSize) 
+			{
+				uUsedSize = (E_UINT32)uLength;
+			}
+
+			// completed if not terminated and write is successful
+			bool terminated = eraserInternalTerminated(context);
+			bCompleted = !terminated &&
+				TRUE == WriteFile(context->m_hFile, context->m_puBuffer,
+				uUsedSize, &uWritten, NULL) &&
+				(uUsedSize == uWritten);
+
+			DWORD le = GetLastError();
+			// flush to disk
+			FlushFileBuffers(context->m_hFile);
+
+			// if not completed - stop!
+			if (!bCompleted) 
+			{
+				break;
+			}
+
+			// set statistics
+			context->m_uProgressWiped += (E_UINT64)uUsedSize;
+			uWiped += (E_UINT64)uUsedSize;
+
+			// how much left to go?
+			uLength -= (E_UINT64)uUsedSize;
+
+			// send update to window
+			postUpdateNotification(context, context->m_lpmMethod->m_nPasses);
+		}
+
+		if (context->m_uTestMode && !eraserInternalTerminated(context)) 
+		{
+			// pause, so the results can be examined
+			context->m_evTestContinue.ResetEvent();
+			eraserTestPausedNotify(context);
+			WaitForSingleObject(context->m_evTestContinue, INFINITE);
+		}
+
+		if (!bCompleted) 
+		{
+			break;
+		}
+	}
+
+	// set statistics
+	setEndStatistics(context, uWiped, uStartTime);
+	return bCompleted;
+
+}
Index: /trunk/EraserDll/Tiger.h
===================================================================
--- /trunk/EraserDll/Tiger.h	(revision 4)
+++ /trunk/EraserDll/Tiger.h	(revision 4)
@@ -0,0 +1,40 @@
+// tiger.h
+//
+// Eraser. Secure data removal. For Windows.
+// Copyright © 1997-2001  Sami Tolvanen (sami@tolvanen.com).
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+
+#ifndef TIGER_H
+#define TIGER_H
+
+/*
+** If you use these, you of course know that state is 24 bytes and that
+** the block size of tiger_compress is 64 bytes
+*/
+
+void tiger_compress(E_PUINT64 block, E_PUINT64 state);
+
+/*
+** Tiger needs one-block (64 bytes) work buffer, if you don't provide it,
+** one will be allocated for you.
+*/
+
+void tiger(E_PUINT64 buffer, E_UINT64 length, E_PUINT64 state, E_PUINT8 work);
+void tiger(E_PUINT64 buffer, E_UINT64 length, E_PUINT64 state);
+
+#endif
Index: /trunk/EraserDll/NTFS.h
===================================================================
--- /trunk/EraserDll/NTFS.h	(revision 4)
+++ /trunk/EraserDll/NTFS.h	(revision 4)
@@ -0,0 +1,320 @@
+// NTFS.h
+//
+// Eraser. Secure data removal. For Windows.
+// Copyright © 1997-2001  Sami Tolvanen (sami@tolvanen.com).
+//
+// Copyright (C) 1997 Mark Russinovich
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#ifndef NTFS_H
+#define NTFS_H
+
+// Header file for defragmentation demonstration program. This file
+// includes definitions for defragmentation File System Control
+// commands, as well as the undocumented NtFsControl call.
+
+//--------------------------------------------------------------------
+//                     D E F I N E S
+//--------------------------------------------------------------------
+
+
+//
+// File System Control commands related to defragging
+//
+#define FSCTL_GET_VOLUME_INFORMATION    0x90064
+#define FSCTL_READ_MFT_RECORD           0x90068
+//GT#define FSCTL_GET_VOLUME_BITMAP         0x9006F
+//GT#define FSCTL_GET_RETRIEVAL_POINTERS    0x90073
+//GT#define FSCTL_MOVE_FILE                 0x90074
+
+//
+// return code type
+//
+typedef LONG NTSTATUS;
+
+//
+// Check for success
+//
+#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)
+
+
+//
+// Error codes returned by NtFsControlFile (see NTSTATUS.H)
+//
+#define STATUS_SUCCESS                   ((NTSTATUS)0x00000000L)
+#define STATUS_BUFFER_OVERFLOW           ((NTSTATUS)0x80000005L)
+#define STATUS_INVALID_PARAMETER         ((NTSTATUS)0xC000000DL)
+#define STATUS_BUFFER_TOO_SMALL          ((NTSTATUS)0xC0000023L)
+#define STATUS_ACCESS_DENIED             ((NTSTATUS)0xC0000011L)
+#define STATUS_ALREADY_COMMITTED         ((NTSTATUS)0xC0000021L)
+#define STATUS_INVALID_DEVICE_REQUEST    ((NTSTATUS)0xC0000010L)
+
+
+//--------------------------------------------------------------------
+//       F S C T L  S P E C I F I C   T Y P E D E F S
+//--------------------------------------------------------------------
+
+
+//
+// This is the definition for a VCN/LCN (virtual cluster/logical cluster)
+// mapping pair that is returned in the buffer passed to
+// FSCTL_GET_RETRIEVAL_POINTERS
+//
+typedef struct {
+    ULONGLONG           Vcn;
+    ULONGLONG           Lcn;
+} MAPPING_PAIR, *PMAPPING_PAIR;
+
+//
+// This is the definition for the buffer that FSCTL_GET_RETRIEVAL_POINTERS
+// returns. It consists of a header followed by mapping pairs
+//
+typedef struct {
+    ULONG               NumberOfPairs;
+    ULONGLONG           StartVcn;
+    MAPPING_PAIR        Pair[1];
+} GET_RETRIEVAL_DESCRIPTOR, *PGET_RETRIEVAL_DESCRIPTOR;
+
+
+//
+// This is the definition of the buffer that FSCTL_GET_VOLUME_BITMAP
+// returns. It consists of a header followed by the actual bitmap data
+//
+typedef struct {
+    ULONGLONG           StartLcn;
+    ULONGLONG           ClustersToEndOfVol;
+    BYTE                Map[1];
+} BITMAP_DESCRIPTOR, *PBITMAP_DESCRIPTOR;
+
+
+//
+// This is the definition for the data structure that is passed in to
+// FSCTL_MOVE_FILE
+//
+typedef struct {
+     HANDLE            FileHandle;
+     ULONG             Reserved;
+     ULONGLONG         StartVcn;
+     ULONGLONG         TargetLcn;
+     ULONG             NumVcns;
+     ULONG             Reserved1;
+} MOVEFILE_DESCRIPTOR, *PMOVEFILE_DESCRIPTOR;
+
+
+//
+// NTFS volume information
+//
+/* GT
+typedef struct {
+    ULONGLONG       SerialNumber;
+    ULONGLONG       NumberOfSectors;
+    ULONGLONG       TotalClusters;
+    ULONGLONG       FreeClusters;
+    ULONGLONG       Reserved;
+    ULONG           BytesPerSector;
+    ULONG           BytesPerCluster;
+    ULONG           BytesPerMFTRecord;
+    ULONG           ClustersPerMFTRecord;
+    ULONGLONG       MFTLength;
+    ULONGLONG       MFTStart;
+    ULONGLONG       MFTMirrorStart;
+    ULONGLONG       MFTZoneStart;
+    ULONGLONG       MFTZoneEnd;
+} NTFS_VOLUME_DATA_BUFFER, *PNTFS_VOLUME_DATA_BUFFER; */
+
+
+
+//--------------------------------------------------------------------
+//     N T F S C O N T R O L F I L E   D E F I N I T I O N S
+//--------------------------------------------------------------------
+
+//
+// Prototype for NtFsControlFile and data structures
+// used in its definition
+//
+
+//
+// Io Status block (see NTDDK.H)
+//
+typedef struct _IO_STATUS_BLOCK {
+    NTSTATUS Status;
+    ULONG Information;
+} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
+
+
+//
+// Apc Routine (see NTDDK.H)
+//
+typedef VOID (*PIO_APC_ROUTINE) (
+                PVOID ApcContext,
+                PIO_STATUS_BLOCK IoStatusBlock,
+                ULONG Reserved
+            );
+
+
+//
+// The undocumented NtFsControlFile
+//
+// This function is used to send File System Control (FSCTL)
+// commands into file system drivers. Its definition is
+// in ntdll.dll (ntdll.lib), a file shipped with the NTDDK.
+//
+typedef NTSTATUS (__stdcall *NTFSCONTROLFILE)(
+                    HANDLE FileHandle,
+                    HANDLE Event,                   // optional
+                    PIO_APC_ROUTINE ApcRoutine,     // optional
+                    PVOID ApcContext,               // optional
+                    PIO_STATUS_BLOCK IoStatusBlock,
+                    ULONG FsControlCode,
+                    PVOID InputBuffer,              // optional
+                    ULONG InputBufferLength,
+                    PVOID OutputBuffer,             // optional
+                    ULONG OutputBufferLength
+            );
+
+
+typedef ULONG (__stdcall *RTLNTSTATUSTODOSERROR) (
+        IN NTSTATUS Status
+        );
+
+
+//
+// File information classes (see NTDDK.H)
+//
+typedef enum _FILE_INFORMATION_CLASS {
+// end_wdm
+    FileDirectoryInformation       = 1,
+    FileFullDirectoryInformation, // 2
+    FileBothDirectoryInformation, // 3
+    FileBasicInformation,         // 4  wdm
+    FileStandardInformation,      // 5  wdm
+    FileInternalInformation,      // 6
+    FileEaInformation,            // 7
+    FileAccessInformation,        // 8
+    FileNameInformation,          // 9
+    FileRenameInformation,        // 10
+    FileLinkInformation,          // 11
+    FileNamesInformation,         // 12
+    FileDispositionInformation,   // 13
+    FilePositionInformation,      // 14 wdm
+    FileFullEaInformation,        // 15
+    FileModeInformation,          // 16
+    FileAlignmentInformation,     // 17
+    FileAllInformation,           // 18
+    FileAllocationInformation,    // 19
+    FileEndOfFileInformation,     // 20 wdm
+    FileAlternateNameInformation, // 21
+    FileStreamInformation,        // 22
+    FilePipeInformation,          // 23
+    FilePipeLocalInformation,     // 24
+    FilePipeRemoteInformation,    // 25
+    FileMailslotQueryInformation, // 26
+    FileMailslotSetInformation,   // 27
+    FileCompressionInformation,   // 28
+    FileObjectIdInformation,      // 29
+    FileCompletionInformation,    // 30
+    FileMoveClusterInformation,   // 31
+    FileQuotaInformation,         // 32
+    FileReparsePointInformation,  // 33
+    FileNetworkOpenInformation,   // 34
+    FileAttributeTagInformation,  // 35
+    FileTrackingInformation,      // 36
+    FileMaximumInformation
+// begin_wdm
+} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
+
+
+typedef NTSTATUS (__stdcall *NTQUERYINFORMATIONFILE)(
+            IN HANDLE FileHandle,
+            OUT PIO_STATUS_BLOCK IoStatusBlock,
+            OUT PVOID FileInformation,
+            IN ULONG Length,
+            IN FILE_INFORMATION_CLASS FileInformationClass
+            );
+
+
+//
+// Streams information
+//
+#pragma pack(4)
+typedef struct {
+    ULONG               NextEntry;
+    ULONG               NameLength;
+    LARGE_INTEGER       Size;
+    LARGE_INTEGER       AllocationSize;
+    USHORT              Name[1];
+} FILE_STREAM_INFORMATION, *PFILE_STREAM_INFORMATION;
+#pragma pack()
+
+
+
+// error codes
+#define WCF_FAILURE         0
+#define WCF_SUCCESS         1
+#define WCF_NOTCOMPRESSED   2
+#define WCF_NOACCESS        3
+
+// structure for function pointers
+typedef struct _NTFSContext {
+    _NTFSContext() :
+        NtFsControlFile(0),
+        NtQueryInformationFile(0),
+        RtlNtStatusToDosError(0),
+        m_hNTDLL(NULL),
+        m_hVolume(INVALID_HANDLE_VALUE)
+    {}
+
+    ~_NTFSContext() {
+        NtFsControlFile = 0;
+        NtQueryInformationFile = 0;
+        RtlNtStatusToDosError = 0;
+
+        if (m_hNTDLL != NULL) {
+            AfxFreeLibrary(m_hNTDLL);
+            m_hNTDLL = NULL;
+        }
+        if (m_hVolume != INVALID_HANDLE_VALUE) {
+            CloseHandle(m_hVolume);
+            m_hVolume = INVALID_HANDLE_VALUE;
+        }
+    }
+
+    // functions
+    NTFSCONTROLFILE NtFsControlFile;
+    NTQUERYINFORMATIONFILE NtQueryInformationFile;
+    RTLNTSTATUSTODOSERROR RtlNtStatusToDosError;
+
+    // handles
+    HINSTANCE m_hNTDLL;
+    HANDLE m_hVolume;
+} NTFSContext;
+
+
+// functions exported from this module
+bool
+findAlternateDataStreams(CEraserContext *context, LPCTSTR szFile, DataStreamArray& streams);
+
+bool
+wipeMFTRecords(CEraserContext *context);
+
+bool
+wipeNTFSFileEntries(CEraserContext *context);
+
+E_UINT32
+wipeCompressedFile(CEraserContext *context);
+
+#endif
Index: /trunk/EraserDll/FAT.h
===================================================================
--- /trunk/EraserDll/FAT.h	(revision 4)
+++ /trunk/EraserDll/FAT.h	(revision 4)
@@ -0,0 +1,325 @@
+// FAT.h
+//
+// Eraser. Secure data removal. For Windows.
+// Copyright © 1997-2001  Sami Tolvanen (sami@tolvanen.com).
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#ifndef FAT_H
+#define FAT_H
+
+///////////////////////////////////////////////////////////////////////////////
+// structures and definitions for calling system interrupts using
+// DeviceIoControl
+
+#define VWIN32_DIOC_DOS_IOCTL       1
+#define VWIN32_DIOC_DOS_INT25       2
+#define VWIN32_DIOC_DOS_INT26       3
+#define VWIN32_DIOC_DOS_DRIVEINFO   6
+
+typedef struct _DIOC_REGISTERS
+{
+    E_UINT32 reg_EBX;
+    E_UINT32 reg_EDX;
+    E_UINT32 reg_ECX;
+    E_UINT32 reg_EAX;
+    E_UINT32 reg_EDI;
+    E_UINT32 reg_ESI;
+    E_UINT32 reg_Flags;
+}
+DIOC_REGISTERS, *PDIOC_REGISTERS;
+
+#define CARRY_FLAG      1
+
+#define LEVEL1_LOCK     1
+#define LEVEL2_LOCK     2
+#define LEVEL3_LOCK     3
+
+// allow everything
+
+#define LOCK_MAX_PERMISSION  0x001
+
+// all MS-DOS data structures must be packed on a one-byte boundary.
+
+#pragma pack(1)
+
+typedef struct _DISKIO
+{
+    E_UINT32 diStartSector;        // sector number to start at
+    E_UINT16 diSectors;            // number of sectors
+    E_UINT32 diBuffer;             // address of buffer
+}
+DISKIO, *PDISKIO;
+
+
+typedef struct _BOOTSECT
+{
+    E_UINT8    bsJump[3];          // jmp to executable code
+    E_UINT8    bsOemName[8];       // OEM name and version
+
+    // BPB (BIOS Parameter Block)
+    E_UINT16   bsBytesPerSec;      // bytes per sector
+    E_UINT8    bsSecPerClust;      // sectors per cluster
+    E_UINT16   bsResSectors;       // number of reserved sectors (starting at 0)
+    E_UINT8    bsFATs;             // number of file allocation tables
+    E_UINT16   bsRootDirEnts;      // number of root-directory entries (directory size)
+    E_UINT16   bsSectors;          // total number of sectors (0 if partition > 32Mb)
+    E_UINT8    bsMedia;            // media descriptor
+    E_UINT16   bsFATsecs;          // number of sectors per FAT
+    E_UINT16   bsSecPerTrack;      // number of sectors per track
+    E_UINT16   bsHeads;            // number of read/write heads
+    E_UINT32   bsHiddenSectors;    // number of hidden sectors
+    E_UINT32   bsHugeSectors;      // number of sectors if bsSectors is 0
+
+    E_UINT8    bsDriveNumber;      // 80h if first hard drive
+    E_UINT8    bsReserved;
+    E_UINT8    bsBootSignature;    // 29h if extended boot-signature record
+    E_UINT32   bsVolumeID;         // volume ID number
+    E_UINT8    bsVolumeLabel[11];  // volume label
+    E_UINT8    bsFileSysType[8];   // file-system type (FAT12 or FAT16)
+}
+BOOTSECTOR, *PBOOTSECTOR;
+
+typedef struct _DIRENTRY
+{
+    E_UINT8    deName[8];          // base name
+    E_UINT8    deExtension[3];     // extension
+    E_UINT8    deAttributes;       // file or directory attributes
+    E_UINT8    deReserved[6];
+    E_UINT16   deLastAccessDate;   // *New Win95* - last access date
+    E_UINT16   deEAhandle;         // *New FAT32* - high word of starting cluster
+    E_UINT16   deCreateTime;       // creation or last modification time
+    E_UINT16   deCreateDate;       // creation or last modification date
+    E_UINT16   deStartCluster;     // starting cluster of the file or directory
+    E_UINT32   deFileSize;         // size of the file in bytes
+}
+DIRENTRY, *PDIRENTRY;
+
+typedef struct _LONGDIRENTRY
+{
+    E_UINT8   leSequence;         // sequence byte:1,2,3,..., last entry is or'ed with 40h
+    wchar_t   leName[5];          // Unicode characters of name
+    E_UINT8   leAttributes;       // Attributes: 0fh
+    E_UINT8   leType;             // Long Entry Type: 0
+    E_UINT8   leChksum;           // Checksum for matching short name alias
+    wchar_t   leName2[6];         // More Unicode characters of name
+    E_UINT16  leZero;             // reserved
+    wchar_t   leName3[2];         // More Unicode characters of name
+}
+LONGDIRENTRY, *PLONGDIRENTRY;
+
+// BPB for a FAT32 partition
+typedef struct _A_BF_BPB
+{
+    E_UINT16    A_BF_BPB_BytesPerSector;
+    E_UINT8     A_BF_BPB_SectorsPerCluster;
+    E_UINT16    A_BF_BPB_ReservedSectors;
+    E_UINT8     A_BF_BPB_NumberOfFATs;
+    E_UINT16    A_BF_BPB_RootEntries;           // Ignored on FAT32 drives
+    E_UINT16    A_BF_BPB_TotalSectors;
+    E_UINT8     A_BF_BPB_MediaDescriptor;
+    E_UINT16    A_BF_BPB_SectorsPerFAT;         // Always 0 on FAT32 BPB
+    E_UINT16    A_BF_BPB_SectorsPerTrack;
+    E_UINT16    A_BF_BPB_Heads;
+    E_UINT16    A_BF_BPB_HiddenSectors;
+    E_UINT16    A_BF_BPB_HiddenSectorsHigh;
+    E_UINT16    A_BF_BPB_BigTotalSectors;
+    E_UINT16    A_BF_BPB_BigTotalSectorsHigh;
+    E_UINT16    A_BF_BPB_BigSectorsPerFat;
+    E_UINT16    A_BF_BPB_BigSectorsPerFatHi;
+    E_UINT16    A_BF_BPB_ExtFlags;
+    E_UINT16    A_BF_BPB_FS_Version;
+    E_UINT16    A_BF_BPB_RootDirStrtClus;
+    E_UINT16    A_BF_BPB_RootDirStrtClusHi;
+    E_UINT16    A_BF_BPB_FSInfoSec;
+    E_UINT16    A_BF_BPB_BkUpBootSec;
+    E_UINT16    A_BF_BPB_Reserved[6];
+}
+A_BF_BPB, PA_BF_BPB;
+
+typedef struct _BOOTSECT32
+{
+    E_UINT8    bsJump[3];          // jmp instruction
+    E_UINT8    bsOemName[8];       // OEM name and version
+
+    // This portion is the FAT32 BPB
+    A_BF_BPB  bpb;
+
+    E_UINT8    bsDriveNumber;      // 80h if first hard drive
+    E_UINT8    bsReserved;
+    E_UINT8    bsBootSignature;    // 29h if extended boot-signature record
+    E_UINT32   bsVolumeID;         // volume ID number
+    E_UINT8    bsVolumeLabel[11];  // volume label
+    E_UINT8    bsFileSysType[8];   // file-system type (FAT32)
+}
+BOOTSECTOR32, *PBOOTSECTOR32;
+
+#pragma pack()
+
+///////////////////////////////////////////////////////////////////////////////
+// DISKERROR values
+
+typedef E_INT32                 DISKERROR;
+#define DISK_FAILURE            -1
+#define DISK_SUCCESS            0
+#define DISK_NOP                1
+#define DISK_WRITE              2
+
+///////////////////////////////////////////////////////////////////////////////
+// type definitions for function pointers
+
+struct wfeInfo;
+
+typedef DISKERROR (*READSECTORS)(wfeInfo* /*pwInfo*/, E_UINT32 /*startSector*/, E_UINT16 /*sectorCount*/, E_PUINT8 /*pBuffer*/);
+typedef DISKERROR (*WRITESECTORS)(wfeInfo* /*pwInfo*/, E_UINT32 /*startSector*/, E_UINT16 /*sectorCount*/, E_PUINT8 /*pBuffer*/);
+typedef DISKERROR (*LOCKVOLUME)(wfeInfo* /*pwInfo*/, E_INT32 /*lockLevel*/, E_INT32 /*permissions*/);
+typedef DISKERROR (*UNLOCKVOLUME)(wfeInfo* /*pwInfo*/);
+typedef DISKERROR (*LOCKSTATE)(wfeInfo* /*pwInfo*/);
+typedef DISKERROR (*LOCKDIRECTORY)(wfeInfo* /*pwInfo*/, LPCTSTR /*directory*/);
+typedef DISKERROR (*UNLOCKDIRECTORY)(wfeInfo* /*pwInfo*/);
+typedef E_UINT32 (*FATITEM)(E_PUINT8 /*buffer*/, E_UINT32 /*index*/);
+typedef void (*FATINFO)(wfeInfo* /*pwInfo*/, E_PUINT8 /*bootSector*/);
+
+typedef struct _DirectoryInformation
+{
+    _DirectoryInformation() :
+        uCluster((E_UINT32)-1) {
+    }
+
+    E_UINT32    uCluster;
+    CString     strPath;
+
+} DIRINFO;
+
+///////////////////////////////////////////////////////////////////////////////
+// FATContext
+
+typedef struct _FATContext
+{
+    _FATContext() {
+        ZeroMemory(this, sizeof(_FATContext));
+    }
+
+    // pointers to file system specific functions
+    READSECTORS     readSectors;
+    WRITESECTORS    writeSectors;
+    FATITEM         item;
+    LOCKVOLUME      lockVolume;
+    UNLOCKVOLUME    unlockVolume;
+    LOCKSTATE       lockState;
+    LOCKDIRECTORY   lockDirectory;
+    UNLOCKDIRECTORY unlockDirectory;
+    FATINFO         getInfo;
+
+    // file system dependent values
+    E_UINT32 uHighValue;
+    E_UINT32 uLowValue;
+    E_UINT32 uErrorValue;
+
+} FATContext;
+
+///////////////////////////////////////////////////////////////////////////////
+// Wipe File Entries info structure passed to functions
+
+// return values
+#define WFE_FAILURE         0
+#define WFE_SUCCESS         1
+#define WFE_NOT_SUPPORTED   2
+#define WFE_DISKMODIFIED    3
+#define WFE_FATERROR        4
+#define WFE_CHANGED         5
+
+#include "Stack.h"
+
+struct wfeInfo
+{
+    wfeInfo() {
+        m_iVolume            = 0;
+        m_uVolumeLocked      = 0;
+        m_hVolume            = INVALID_HANDLE_VALUE;
+        m_hDirectory         = INVALID_HANDLE_VALUE;
+        m_uSectorsPerCluster = 0;
+        m_uSectorSize        = 0;
+        m_uSectorsPerFAT     = 0;
+        m_uReservedSectors   = 0;
+        m_uStartSector       = 0;
+        m_uSectorsTotal      = 0;
+        m_uClusterSize       = 0;
+        m_uClustersTotal     = 0;
+        m_uFATDirectorySize  = 0;
+        m_uFATDirectoryStart = 0;
+        m_pFAT               = 0;
+    }
+
+    ~wfeInfo() {
+        if (m_hVolume != INVALID_HANDLE_VALUE) {
+            CloseHandle(m_hVolume);
+            m_hVolume = INVALID_HANDLE_VALUE;
+        }
+        if (isWindowsNT && m_hDirectory != INVALID_HANDLE_VALUE) {
+            CloseHandle(m_hDirectory);
+            m_hDirectory = INVALID_HANDLE_VALUE;
+        }
+        if (m_pFAT) {
+            delete[] m_pFAT;
+            m_pFAT = 0;
+        }
+    }
+
+    // drive
+    E_INT32   m_iVolume;                      // volume (1-based)
+    E_UINT8   m_uVolumeLocked;                // lock state (NT)
+
+    // handles
+    HANDLE    m_hVolume;                      // handle to VWIN32 VxD (9x) or volume (NT)
+    HANDLE    m_hDirectory;                   // handle to directory (NT)
+
+    // sectors and FAT information
+    E_UINT16  m_uSectorsPerCluster;           // sectors per cluster
+    E_UINT16  m_uSectorSize;                  // sector size
+    E_UINT16  m_uSectorsPerFAT;               // FAT síze (in sectors)
+
+    E_UINT32  m_uReservedSectors;             // reserved sectors
+    E_UINT32  m_uStartSector;                 // beginning of the data area
+    E_UINT32  m_uSectorsTotal;                // sectors
+
+    // clusters
+    E_UINT32  m_uClusterSize;                 // cluster size
+    E_UINT32  m_uClustersTotal;               // number of clusters
+
+    // directories
+    E_UINT16  m_uFATDirectorySize;            // size of FAT root directory
+    E_UINT32  m_uFATDirectoryStart;           // the directory cluster (FAT32) or
+                                              // start sector (FAT)
+    CStack<DIRINFO> m_stDirectories;          // directories
+
+    // FAT
+    E_PUINT8  m_pFAT;                       // FAT buffer
+
+    // filesystem specific data
+    FATContext FS;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// functions exported from the module
+
+bool
+getFATClusterAndSectorSize(LPCTSTR szDrive, E_UINT32& uCluster, E_UINT32& uSector);
+
+E_UINT32
+wipeFATFileEntries(CEraserContext *context, LPCTSTR szRetryMessage);
+
+#endif
Index: /trunk/EraserDll/FileLockResolver.h
===================================================================
--- /trunk/EraserDll/FileLockResolver.h	(revision 4)
+++ /trunk/EraserDll/FileLockResolver.h	(revision 4)
@@ -0,0 +1,30 @@
+#pragma once
+#include "EraserDll.h"
+
+class ERASER_API CFileLockResolver
+{
+public:
+	
+	CFileLockResolver(BOOL = FALSE);
+	~CFileLockResolver(void);
+	void Close();
+private:
+	
+	CFileLockResolver(ERASER_HANDLE, BOOL);
+	inline void AskUser(BOOL val)
+	{
+		m_bAskUser = val;
+	}
+public:
+	void SetHandle(ERASER_HANDLE);
+	static void Resolve(LPCTSTR szFileName, CStringArray&);
+	static void Resolve(LPCTSTR szFileName);
+private:
+	BOOL m_bAskUser;	
+	CString m_strLockFileList;
+	ERASER_HANDLE m_hHandle;
+private:
+	void HandleError(LPCTSTR szFileName, DWORD dwErrorCode, int method, unsigned int passes);
+	static DWORD ErrorHandler(LPCTSTR szFileName, DWORD dwErrorCode, void* ctx, void* param);
+};
+
Index: /trunk/EraserDll/FillMemoryWith.h
===================================================================
--- /trunk/EraserDll/FillMemoryWith.h	(revision 4)
+++ /trunk/EraserDll/FillMemoryWith.h	(revision 4)
@@ -0,0 +1,27 @@
+// FillMemoryWith.h
+//
+// Eraser. Secure data removal. For Windows.
+// Copyright © 1997-2001  Sami Tolvanen (sami@tolvanen.com).
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#ifndef FILLMEMORYWITH_H
+#define FILLMEMORYWITH_H
+
+void
+FillMemoryWith(LPVOID, E_UINT32, E_UINT8, ...);
+
+#endif
Index: /trunk/EraserDll/OptionsDlg.cpp
===================================================================
--- /trunk/EraserDll/OptionsDlg.cpp	(revision 4)
+++ /trunk/EraserDll/OptionsDlg.cpp	(revision 4)
@@ -0,0 +1,75 @@
+// OptionsDlg.cpp
+//
+// Eraser. Secure data removal. For Windows.
+// Copyright © 1997-2001  Sami Tolvanen (sami@tolvanen.com).
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#include "stdafx.h"
+#include "resource.h"
+#include "Eraser.h"
+#include "eraserdll.h"
+#include "options.h"
+#include "OptionsDlg.h"
+
+#ifdef _DEBUG
+#undef THIS_FILE
+static char BASED_CODE THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// COptionsDlg
+
+IMPLEMENT_DYNAMIC(COptionsDlg, CPropertySheet)
+
+COptionsDlg::COptionsDlg(CWnd* pWndParent) :
+CPropertySheet(IDS_PROPSHT_CAPTION, pWndParent)
+{
+    // Add all of the property pages here.  Note that
+    // the order that they appear in here will be
+    // the order they appear in on screen.  By default,
+    // the first page of the set is the active one.
+    // One way to make a different property page the
+    // active one is to call SetActivePage().
+
+    m_psh.dwFlags |= PSH_NOAPPLYNOW;
+    m_psh.dwFlags &= (~PSH_HASHELP);
+
+    m_pgFiles.SetLibSettings(&m_lsSettings);
+    m_pgFiles.SetFreeSpaceOpt(&m_pgFreeSpace);
+
+    m_pgFreeSpace.m_plsSettings = &m_lsSettings;
+    m_pgFreeSpace.m_ppgFiles    = &m_pgFiles;
+
+    AddPage(&m_pgFiles);
+    AddPage(&m_pgFreeSpace);
+}
+
+COptionsDlg::~COptionsDlg()
+{
+
+}
+
+
+BEGIN_MESSAGE_MAP(COptionsDlg, CPropertySheet)
+    //{{AFX_MSG_MAP(COptionsDlg)
+        // NOTE - the ClassWizard will add and remove mapping macros here.
+    //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+
+/////////////////////////////////////////////////////////////////////////////
+// COptionsDlg message handlers
Index: /trunk/EraserDll/RND.cpp
===================================================================
--- /trunk/EraserDll/RND.cpp	(revision 4)
+++ /trunk/EraserDll/RND.cpp	(revision 4)
@@ -0,0 +1,104 @@
+// RND.cpp
+//
+// Eraser. Secure data removal. For Windows.
+// Copyright © 1997-2001  Sami Tolvanen (sami@tolvanen.com).
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#include "stdafx.h"
+#include "EraserDll.h"
+#include "Common.h"
+#include "RND.h"
+
+bool
+wipeFileWithPseudoRandom(CEraserContext *context)
+{
+    E_UINT32 uStartTime = GetTickCount();
+    E_UINT32 uUsedSize  = 0;
+    E_UINT32 uSavedSize = 0;
+    E_UINT64 uLength    = 0;
+    E_UINT64 uWiped     = 0;
+    E_UINT32 uWritten   = 0;
+    bool     bCompleted = true;
+
+    // send the begin message only once
+    postStartNotification(context);
+
+    setBufferSize(context, uSavedSize);
+
+    for (E_UINT16 uCurrentPass = 0; uCurrentPass < context->m_lpmMethod->m_nPasses; uCurrentPass++) {
+        eraserSafeAssign(context, context->m_uProgressCurrentPass, (E_UINT16)(uCurrentPass + 1));
+
+        // start from the beginning again
+        SetFilePointer(context->m_hFile, context->m_uiFileStart.LowPart,
+                       (E_PINT32)&context->m_uiFileStart.HighPart, FILE_BEGIN);
+
+        uLength = context->m_uiFileSize.QuadPart;
+        uUsedSize = uSavedSize;
+
+        while (uLength > 0) {
+            // random data needs refilling
+            isaacFill((E_PUINT8)context->m_puBuffer, uUsedSize);
+
+            // use the whole buffer as long as we can
+            if (uLength < (E_UINT64)uUsedSize) {
+                uUsedSize = (E_UINT32)uLength;
+            }
+
+            // completed if not terminated and write is successful
+			bool terminated = eraserInternalTerminated(context);
+            bCompleted = !terminated &&
+                         TRUE == WriteFile(context->m_hFile, context->m_puBuffer,
+                                   uUsedSize, &uWritten, NULL) &&
+                         (uUsedSize == uWritten);
+
+			DWORD le = GetLastError();
+            // flush to disk
+            FlushFileBuffers(context->m_hFile);
+
+            // if not completed - stop!
+            if (!bCompleted) {
+                break;
+            }
+
+            // set statistics
+            context->m_uProgressWiped += (E_UINT64)uUsedSize;
+            uWiped += (E_UINT64)uUsedSize;
+
+            // how much left to go?
+            uLength -= (E_UINT64)uUsedSize;
+
+            // send update to window
+            postUpdateNotification(context, context->m_lpmMethod->m_nPasses);
+        }
+
+        if (context->m_uTestMode && !eraserInternalTerminated(context)) {
+            // pause, so the results can be examined
+            context->m_evTestContinue.ResetEvent();
+            eraserTestPausedNotify(context);
+            WaitForSingleObject(context->m_evTestContinue, INFINITE);
+        }
+
+        if (!bCompleted) {
+            break;
+        }
+    }
+
+    // set statistics
+    setEndStatistics(context, uWiped, uStartTime);
+
+    return bCompleted;
+}
Index: /trunk/EraserDll/Schneier7pass.h
===================================================================
--- /trunk/EraserDll/Schneier7pass.h	(revision 4)
+++ /trunk/EraserDll/Schneier7pass.h	(revision 4)
@@ -0,0 +1,5 @@
+#ifndef _SCHNEIER7PASS_H_
+#define _SCHNEIER7PASS_H_
+class CEraserContext;
+bool wipeFileWithSchneier7Pass(CEraserContext *context);
+#endif
Index: /trunk/EraserDll/File.h
===================================================================
--- /trunk/EraserDll/File.h	(revision 4)
+++ /trunk/EraserDll/File.h	(revision 4)
@@ -0,0 +1,56 @@
+// File.h
+//
+// Eraser. Secure data removal. For Windows.
+// Copyright © 1997-2001  Sami Tolvanen (sami@tolvanen.com).
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#ifndef FILE_H
+#define FILE_H
+
+typedef class _DataStream {
+public:
+    _DataStream() {
+        clear();
+    }
+
+    ~_DataStream() {
+        clear();
+    }
+
+    CString m_strName;
+    E_UINT64 m_uSize;
+    bool m_bDefault;
+
+private:
+    void clear() {
+        m_strName.Empty();
+        m_uSize = 0;
+        m_bDefault = false;
+    }
+
+} DataStream;
+
+typedef CArray<DataStream, DataStream&> DataStreamArray;
+
+
+bool
+resetDate(HANDLE hFile);
+
+bool
+wipeFile(CEraserContext *context);
+
+#endif
Index: /trunk/EraserDll/Random.h
===================================================================
--- /trunk/EraserDll/Random.h	(revision 4)
+++ /trunk/EraserDll/Random.h	(revision 4)
@@ -0,0 +1,244 @@
+// Random.h
+//
+// Constants and function definitions.
+//
+// Eraser. Secure data removal. For Windows.
+// Copyright © 1997-2001  Sami Tolvanen (sami@tolvanen.com).
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#ifndef RANDOM_H
+#define RANDOM_H
+
+#include <wincrypt.h>   /* CryptoAPI */
+#include <tlhelp32.h>   /* ToolHelp  */
+
+/*
+** CryptoAPI definitions and constants
+*/
+
+/* Module name */
+const LPCTSTR RANDOM_MODULE_ADVAPI32 = "ADVAPI32.DLL";
+#ifdef DMARS
+#define ULONG_PTR DWORD
+#endif
+/* Function definitions */
+typedef BOOL (WINAPI *CRYPTACQUIRECONTEXT)(HCRYPTPROV*, LPCTSTR, LPCTSTR, DWORD, DWORD);
+typedef BOOL (WINAPI *CRYPTGENRANDOM)(HCRYPTPROV, DWORD, BYTE*);
+typedef BOOL (WINAPI *CRYPTRELEASECONTEXT)(HCRYPTPROV, ULONG_PTR);
+
+/* Function names */
+const LPCTSTR RANDOM_FUNCTION_CRYPTACQUIRECONTEXT = "CryptAcquireContextA";
+const LPCTSTR RANDOM_FUNCTION_CRYPTGENRANDOM      = "CryptGenRandom";
+const LPCTSTR RANDOM_FUNCTION_CRYPTRELEASECONTEXT = "CryptReleaseContext";
+
+/* Constants */
+const E_UINT32 fastPollSize = 20;   /* 160 bits */
+const E_UINT32 slowPollSize = 64;   /* 512 bits */
+
+/* Intel i8xx (82802 Firmware Hub Device) hardware random number generator */
+#ifndef INTEL_DEF_PROV
+#define INTEL_DEF_PROV  "Intel Hardware Cryptographic Service Provider"
+#endif
+
+
+/*
+** Windows ToolHelp32 API definitions and constants
+*/
+
+/* Module name */
+const LPCTSTR RANDOM_MODULE_KERNEL32 = "KERNEL32.DLL";
+
+/* Function definitions */
+typedef BOOL (WINAPI *MODULEWALK)(HANDLE hSnapshot, LPMODULEENTRY32 lpme);
+typedef BOOL (WINAPI *THREADWALK)(HANDLE hSnapshot, LPTHREADENTRY32 lpte);
+typedef BOOL (WINAPI *PROCESSWALK)(HANDLE hSnapshot, LPPROCESSENTRY32 lppe);
+typedef BOOL (WINAPI *HEAPLISTWALK)(HANDLE hSnapshot, LPHEAPLIST32 lphl);
+typedef BOOL (WINAPI *HEAPFIRST)(LPHEAPENTRY32 lphe, DWORD th32ProcessID, DWORD th32HeapID);
+typedef BOOL (WINAPI *HEAPNEXT)(LPHEAPENTRY32 lphe);
+typedef HANDLE (WINAPI *CREATESNAPSHOT)(DWORD dwFlags, DWORD th32ProcessID);
+
+/* Function names */
+const LPCTSTR RANDOM_FUNCTION_MODULE32FIRST   = "Module32First";
+const LPCTSTR RANDOM_FUNCTION_MODULE32NEXT    = "Module32Next";
+const LPCTSTR RANDOM_FUNCTION_THREAD32FIRST   = "Thread32First";
+const LPCTSTR RANDOM_FUNCTION_THREAD32NEXT    = "Thread32Next";
+const LPCTSTR RANDOM_FUNCTION_PROCESS32FIRST  = "Process32First";
+const LPCTSTR RANDOM_FUNCTION_PROCESS32NEXT   = "Process32Next";
+const LPCTSTR RANDOM_FUNCTION_HEAP32LISTFIRST = "Heap32ListFirst";
+const LPCTSTR RANDOM_FUNCTION_HEAP32LISTNEXT  = "Heap32ListNext";
+const LPCTSTR RANDOM_FUNCTION_HEAPFIRST       = "Heap32First";
+const LPCTSTR RANDOM_FUNCTION_HEAPNEXT        = "Heap32Next";
+const LPCTSTR RANDOM_FUNCTION_CREATESNAPSHOT  = "CreateToolhelp32Snapshot";
+
+
+/*
+** Windows NT NetAPI32 definitions and constants
+*/
+
+/* Module name */
+const LPCTSTR RANDOM_MODULE_NETAPI = "NETAPI32.DLL";
+
+/* Function definitions */
+typedef DWORD (WINAPI *NETSTATISTICSGET2)(LPWSTR szServer, LPWSTR szService,
+                                          DWORD dwLevel, DWORD dwOptions,
+                                          LPBYTE *lpBuffer);
+typedef DWORD (WINAPI *NETAPIBUFFERSIZE)(LPVOID lpBuffer, LPDWORD cbBuffer);
+typedef DWORD (WINAPI *NETAPIBUFFERFREE)(LPVOID lpBuffer);
+
+/* Function names */
+const LPCTSTR RANDOM_FUNCTION_NETSTATISTICSGET2 = "NetStatisticsGet2";
+const LPCTSTR RANDOM_FUNCTION_NETAPIBUFFERSIZE  = "NetApiBufferSize";
+const LPCTSTR RANDOM_FUNCTION_NETAPIBUFFERFREE  = "NetApiBufferFree";
+
+/* Constants */
+const LPCTSTR RANDOM_KEY_PRODUCTOPTIONS  = "SYSTEM\\CurrentControlSet\\Control\\ProductOptions";
+const LPCTSTR RANDOM_KEY_PRODUCTTYPE     = "ProductType";
+const LPCTSTR RANDOM_NTWORKSTATION_TOKEN = "WinNT";
+
+#undef SERVICE_WORKSTATION
+#undef SERVICE_SERVER
+const LPWSTR SERVICE_WORKSTATION = L"LanmanWorkstation";
+const LPWSTR SERVICE_SERVER      = L"LanmanServer";
+
+/*
+** Windows NT Native functions
+*/
+
+/* Module name */
+const LPCTSTR RANDOM_MODULE_NTDLL = "NTDLL.DLL";
+
+/* Function definitions */
+typedef DWORD (WINAPI *NTQUERYSYSTEMINFO)(DWORD dwType, DWORD dwData,
+                                          DWORD dwMaxSize, DWORD dwDataSize);
+
+/* Function names */
+const LPCTSTR RANDOM_FUNCTION_NTQUERYSYSTEMINFO = "NtQuerySystemInformation";
+
+/* Constants */
+#define PERFORMANCE_BUFFER_SIZE     65536   /* Start at 64K */
+#define PERFORMANCE_BUFFER_STEP     16384   /* Step by 16K */
+
+
+/*
+** ISAAC pseudorandom number generator definitions and constants
+*/
+
+#define RANDOM_ISAAC_LOG        8
+#define RANDOM_ISAAC_WORDS      (1 << RANDOM_ISAAC_LOG)
+#define RANDOM_ISAAC_BYTES      (RANDOM_ISAAC_WORDS * sizeof(E_UINT32))
+
+#pragma pack(4)
+
+typedef struct __isaacState {
+    E_UINT32 mm[RANDOM_ISAAC_WORDS];
+    E_UINT32 a;
+    E_UINT32 b;
+    E_UINT32 c;
+} ISAAC_STATE;
+
+#pragma pack()
+
+/*
+** Page allocation and pool management constants
+*/
+
+/*
+** Page structure:
+**
+**  [52 bytes][1036 bytes][1024 bytes][480 bytes][480 bytes][1024 bytes] = 4096 bytes
+**       1          2           3          4          5           6
+**
+**  1. Unused (non-random data)
+**  2. ISAAC_STATE
+**  3. ISAAC output buffer
+**  4. Entropy pool
+**  5. Used as a work buffer when creating output
+**  6. Used as temporary work buffer
+*/
+
+const E_UINT32 entropyPoolSize = 480;
+const E_UINT32 outputSize = entropyPoolSize / 2;
+
+const E_UINT32 unusedSize = 52;
+const E_UINT32 isaacStateOffset = unusedSize;
+const E_UINT32 isaacOutputOffset = isaacStateOffset + sizeof(ISAAC_STATE);
+const E_UINT32 poolOffset = isaacOutputOffset + RANDOM_ISAAC_BYTES;
+const E_UINT32 outputOffset = poolOffset + entropyPoolSize;
+const E_UINT32 tempOffset = outputOffset + entropyPoolSize;
+
+/*
+** Constants
+*/
+
+const E_UINT32 qualityFastPoll = 34;
+const E_UINT32 qualitySlowPoll = 100;
+const E_UINT32 qualityMicrosoft = qualityFastPoll;
+const E_UINT32 qualityIntel = 90;
+
+const E_UINT32 requiredQuality = 100;
+const E_UINT32 requiredMixes = 10;
+
+const E_UINT32 slowPollWait = 30000;
+const E_UINT32 threadTermination = 5000;
+
+const E_UINT32 pageSize = 4096;
+
+/*
+** Hash function properties
+*/
+
+const E_UINT32 hashSize = 24;          // hash function's digest size
+const E_UINT32 blockSize = 64;         // hash function's block size
+
+const E_UINT32 dataSize = 104;         // additional data hashed when mixing
+const E_UINT32 mixSize = 2* blockSize; // = hashSize + dataSize
+
+/*
+** Pool refresh
+*/
+
+const E_UINT32 poolTouchInterval = 2000;  // milliseconds
+const E_UINT32 poolMoveInterval = 300000;
+
+/*
+** ISAAC seed size
+*/
+
+const E_UINT32 RANDOM_ISAAC_SEED_BYTES = outputSize;
+
+
+
+/*
+** Exported functions
+*/
+
+void
+randomInit();
+void
+randomEnd();
+
+void
+randomAddEntropy(E_PUINT8, E_UINT32);
+bool
+randomFill(E_PUINT8, E_UINT32);
+
+void
+isaacSeed();
+bool
+isaacFill(E_PUINT8, E_UINT32);
+
+#endif
Index: /trunk/EraserDll/CustomMethodEdit.h
===================================================================
--- /trunk/EraserDll/CustomMethodEdit.h	(revision 4)
+++ /trunk/EraserDll/CustomMethodEdit.h	(revision 4)
@@ -0,0 +1,99 @@
+// CustomEdit.h
+//
+// Eraser. Secure data removal. For Windows.
+// Copyright © 1997-2001  Sami Tolvanen (sami@tolvanen.com).
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#if !defined(AFX_CUSTOMMETHODEDIT_H__0C74CCD1_BC7D_11D3_82A0_000000000000__INCLUDED_)
+#define AFX_CUSTOMMETHODEDIT_H__0C74CCD1_BC7D_11D3_82A0_000000000000__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+#include "../shared/FlatListCtrl.h"
+#include "ByteEdit.h"
+#include "Pass.h"
+#include "commctrl.h"
+
+/////////////////////////////////////////////////////////////////////////////
+// CCustomMethodEdit dialog
+
+class ERASER_API CCustomMethodEdit : public CDialog
+{
+// Construction
+public:
+    void SaveSelectedPass();
+    void EnablePattern(BOOL bEnable);
+    void UpdateList();
+    BOOL LoadCustomMethod(LPMETHOD);
+    BOOL FillCustomMethod(LPMETHOD);
+    CCustomMethodEdit(CWnd* pParent = NULL);   // standard constructor
+
+    WORD m_nSelectedPass;
+    CArray<PASS, PASS&> m_aPasses;
+
+// Dialog Data
+    //{{AFX_DATA(CCustomMethodEdit)
+    enum { IDD = IDD_DIALOG_METHODEDIT };
+    CByteEdit   m_editByte2;
+    CByteEdit   m_editByte3;
+    CByteEdit   m_editByte1;
+    CFlatListCtrl   m_lcPasses;
+    BOOL    m_bByte2;
+    BOOL    m_bByte3;
+    CString m_strDescription;
+    BOOL    m_bShuffle;
+    //}}AFX_DATA
+
+
+// Overrides
+    // ClassWizard generated virtual function overrides
+    //{{AFX_VIRTUAL(CCustomMethodEdit)
+    protected:
+    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
+    //}}AFX_VIRTUAL
+
+// Implementation
+protected:
+
+    // Generated message map functions
+    //{{AFX_MSG(CCustomMethodEdit)
+    virtual BOOL OnInitDialog();
+    afx_msg void OnButtonAdd();
+    afx_msg void OnButtonCopy();
+    afx_msg void OnButtonDelete();
+    afx_msg void OnButtonDown();
+    afx_msg void OnButtonUp();
+    afx_msg void OnCheckByte2();
+    afx_msg void OnCheckByte3();
+    virtual void OnOK();
+    afx_msg void OnRadioPattern();
+    afx_msg void OnRadioPseudorandom();
+    afx_msg void OnItemchangedListPasses(NMHDR* pNMHDR, LRESULT* pResult);
+    afx_msg void OnChangeEditDescription();
+    afx_msg void OnChangeEditByte1();
+    afx_msg void OnChangeEditByte2();
+    afx_msg void OnChangeEditByte3();
+    //}}AFX_MSG
+    DECLARE_MESSAGE_MAP()
+};
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_CUSTOMMETHODEDIT_H__0C74CCD1_BC7D_11D3_82A0_000000000000__INCLUDED_)
Index: /trunk/EraserDll/Eraser.h
===================================================================
--- /trunk/EraserDll/Eraser.h	(revision 4)
+++ /trunk/EraserDll/Eraser.h	(revision 4)
@@ -0,0 +1,57 @@
+// Eraser.h
+//
+// Eraser. Secure data removal. For Windows.
+// Copyright © 1997-2001  Sami Tolvanen (sami@tolvanen.com).
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#ifndef ERASER_H
+#define ERASER_H
+
+#ifndef __AFXWIN_H__
+    #error include 'stdafx.h' before including this file for PCH
+#endif
+
+#include "resource.h"       // main symbols
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CEraserApp
+// See Eraser.cpp for the implementation of this class
+//
+
+class CEraserApp : public CWinApp
+{
+public:
+    CEraserApp();
+
+// Overrides
+    // ClassWizard generated virtual function overrides
+    //{{AFX_VIRTUAL(CEraserApp)
+	public:
+    virtual BOOL InitInstance();
+	virtual int ExitInstance();
+	//}}AFX_VIRTUAL
+
+    //{{AFX_MSG(CEraserApp)
+        // NOTE - the ClassWizard will add and remove member functions here.
+        //    DO NOT EDIT what you see in these blocks of generated code !
+    //}}AFX_MSG
+    DECLARE_MESSAGE_MAP()
+};
+/////////////////////////////////////////////////////////////////////////////
+
+#endif
Index: /trunk/EraserDll/StdAfx.cpp
===================================================================
--- /trunk/EraserDll/StdAfx.cpp	(revision 4)
+++ /trunk/EraserDll/StdAfx.cpp	(revision 4)
@@ -0,0 +1,23 @@
+// stdafx.cpp : source file that includes just the standard includes
+//  Eraser.pch will be the pre-compiled header
+//  stdafx.obj will contain the pre-compiled type information
+//
+// Eraser. Secure data removal. For Windows.
+// Copyright © 1997-2001  Sami Tolvanen (sami@tolvanen.com).
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#include "stdafx.h"
Index: /trunk/EraserDll/resource.h
===================================================================
--- /trunk/EraserDll/resource.h	(revision 4)
+++ /trunk/EraserDll/resource.h	(revision 4)
@@ -0,0 +1,79 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by Eraser.rc
+//
+#define IDC_BUTTON_SAVEAS               3
+#define IDS_PROPSHT_CAPTION             105
+#define IDD_PAGE_FILES                  106
+#define IDS_PASSWDNOTMATCH              106
+#define IDD_PAGE_FREESPACE              108
+#define IDS_ERROR_CLUSTER               113
+#define IDS_ERROR_MEMORY                114
+#define IDS_ERROR_INTERNAL              115
+#define IDS_ERROR_DIRECTORY             116
+#define IDS_ERROR_FREESPACE             117
+#define IDS_ERROR_DIRENTRIES            118
+#define IDS_ERROR_DIRENTRIES_FS         119
+#define IDS_ERROR_DIRENTRIES_FAT        120
+#define IDS_ERROR_DIRENTRIES_MAXRESTARTS 121
+#define IDS_ERROR_NODATA                122
+#define IDS_ERROR_DIRECTORY_REMOVE      123
+#define IDS_ERROR_DIRENTRIES_LOCK       124
+#define IDS_ERROR_TEMPFILE              125
+#define IDS_ERROR_ADS                   126
+#define IDR_MAINFRAME                   128
+#define IDS_METHOD_DELETE               130
+#define IDS_METHOD_NOPASSES             131
+#define IDS_METHOD_NONESELECTED         132
+#define IDI_ICON_OPTIONS                134
+#define IDI_ICON_DATA                   138
+#define IDD_DIALOG_METHODEDIT           145
+#define IDD_DIALOG_PASSEDIT             146
+#define IDD_DIALOG_REPORT               147
+#define IDD_DIALOG_SEC_MAN              148
+#define IDC_RADIO_PSEUDORANDOM          1000
+#define IDC_LIST_METHOD                 1021
+#define IDC_BUTTON_NEW                  1022
+#define IDC_BUTTON_DELETE               1023
+#define IDC_BUTTON_EDIT                 1024
+#define IDC_STATIC_SELECTED             1025
+#define IDC_CHECK_FREESPACE             1026
+#define IDC_CHECK_CLUSTERTIPS           1027
+#define IDC_CHECK_DIRECTORYENTRIES      1028
+#define IDC_BUTTON_ADD                  1030
+#define IDC_BUTTON_COPY                 1031
+#define IDC_BUTTON_UP                   1032
+#define IDC_BUTTON_DOWN                 1033
+#define IDC_EDIT_DESCRIPTION            1034
+#define IDC_RADIO_PATTERN               1035
+#define IDC_CHECK_BYTE2                 1037
+#define IDC_CHECK_BYTE3                 1038
+#define IDC_CHECK_SHUFFLE               1040
+#define IDC_EDIT_BYTE1                  1041
+#define IDC_EDIT_BYTE2                  1042
+#define IDC_EDIT_BYTE3                  1043
+#define IDC_LIST_PASSES                 1044
+#define IDC_STATIC_BYTE1                1045
+#define IDC_EDIT_PASSES                 1046
+#define IDC_SPIN_PASSES                 1047
+#define IDC_STATIC_COMPLETION           1048
+#define IDC_EDIT_STATISTICS             1049
+#define IDC_LIST_ERRORS                 1050
+#define IDC_STATIC_FAILURES_HEADER      1051
+#define IDC_CHECK_FILECLUSTERTIPS       1052
+#define IDC_CHECK_FILENAMES             1053
+#define IDC_CHECK_ALTERNATESTREAMS      1054
+#define IDC_EDIT_SECMAN_PASSWD          1055
+#define IDC_EDIT_SECMAN_PASSWDCONFIRM   1057
+#define IDC_STATIC_CONFIRM              1058
+
+// Next default values for new objects
+// 
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE        149
+#define _APS_NEXT_COMMAND_VALUE         32771
+#define _APS_NEXT_CONTROL_VALUE         1059
+#define _APS_NEXT_SYMED_VALUE           113
+#endif
+#endif
Index: /trunk/EraserDll/FreeSpace.cpp
===================================================================
--- /trunk/EraserDll/FreeSpace.cpp	(revision 4)
+++ /trunk/EraserDll/FreeSpace.cpp	(revision 4)
@@ -0,0 +1,610 @@
+// FreeSpace.cpp
+//
+// Eraser. Secure data removal. For Windows.
+// Copyright © 1997-2001  Sami Tolvanen (sami@tolvanen.com).
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#include "stdafx.h"
+#include "resource.h"
+#include "EraserDll.h"
+#include "..\shared\FileHelper.h"
+#include "..\shared\key.h"
+#include "Common.h"
+#include "File.h"
+#include "FAT.h"
+#include "NTFS.h"
+#include "FreeSpace.h"
+#include <winioctl.h>
+
+// Windows 98 - Q188074
+static const LPCTSTR ERASER_REGISTRY_FILESYSTEM
+    = "System\\CurrentControlSet\\Control\\FileSystem";
+static const LPCTSTR ERASER_REGISTRY_LOWDISKSPACE
+    = "DisableLowDiskSpaceBroadcast";
+
+static inline E_UINT32
+disableLowDiskSpaceNotification(TCHAR szDrive)
+{
+    // disables the annoying warning Windows 98 displays when disk space is low
+    if (!isWindowsNT) {
+        CKey kReg;
+        E_UINT32 uOldValue = 0;
+        E_UINT32 uNewValue = (1 << (toupper((E_INT32)szDrive) - (E_INT32)'A'));
+
+        if (kReg.Open(HKEY_LOCAL_MACHINE, ERASER_REGISTRY_FILESYSTEM)) {
+            // save the previous value (if it exists)
+            kReg.GetValue(uOldValue, ERASER_REGISTRY_LOWDISKSPACE, 0);
+            kReg.SetValue(uNewValue, ERASER_REGISTRY_LOWDISKSPACE);
+
+            kReg.Close();
+        }
+        return uOldValue;
+    }
+
+    return 0;
+}
+
+static inline void
+restoreLowDiskSpaceNotification(E_UINT32 uOldValue)
+{
+    // restores the old value for the low disk space notification key
+    if (!isWindowsNT) {
+        CKey kReg;
+        if (kReg.Open(HKEY_LOCAL_MACHINE, ERASER_REGISTRY_FILESYSTEM)) {
+            if (uOldValue != 0) {
+                kReg.SetValue(uOldValue, ERASER_REGISTRY_LOWDISKSPACE);
+            } else {
+                kReg.DeleteValue(ERASER_REGISTRY_LOWDISKSPACE);
+            }
+            kReg.Close();
+        }
+    }
+}
+
+static inline BOOL
+uncompressFolder(LPCTSTR szFolder)
+{
+    // if folder is compressed, this uncompresses it
+    if (isWindowsNT) {
+        HANDLE hHandle = INVALID_HANDLE_VALUE;
+
+        hHandle = CreateFile(szFolder, GENERIC_READ | GENERIC_WRITE, 0, NULL,
+                             OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+
+        if (hHandle != INVALID_HANDLE_VALUE) {
+            BOOL   bSuccess    = FALSE;
+            E_UINT16 uCompressed = COMPRESSION_FORMAT_NONE;
+            E_UINT32 uReturned   = 0;
+
+            bSuccess = DeviceIoControl(hHandle, FSCTL_GET_COMPRESSION, NULL, 0,
+                                       &uCompressed, sizeof(E_UINT16), &uReturned,
+                                       NULL);
+
+            if (bSuccess && (uCompressed != COMPRESSION_FORMAT_NONE)) {
+                // it is compressed - change attributes
+                uCompressed = COMPRESSION_FORMAT_NONE;
+
+                bSuccess = DeviceIoControl(hHandle, FSCTL_SET_COMPRESSION,
+                                           &uCompressed, sizeof(E_UINT16),
+                                           NULL, 0, &uReturned, NULL);
+            }
+
+            CloseHandle(hHandle);
+            return bSuccess;
+        }
+    }
+
+    return FALSE;
+}
+
+bool
+getClusterAndSectorSize(LPCTSTR szDrive, E_UINT32& uCluster, E_UINT32& uSector)
+{
+    uCluster = 0;
+    uSector = DEFAULT_SECTOR_SIZE;
+
+    try {
+        if (isWindowsNT) {
+            // GetDiskFreeSpace will return correct values
+            E_UINT32 uSecPerClus = 0;
+            E_UINT32 uBytPerSec  = 0;
+            E_UINT32 uFreeClus   = 0;
+            E_UINT32 uClus       = 0;
+
+            if (GetDiskFreeSpace(szDrive, &uSecPerClus, &uBytPerSec,
+                                 &uFreeClus, &uClus)) {
+                uSector = uBytPerSec;
+                uCluster = (uSector * uSecPerClus);
+            }
+        } else {
+            // GetDiskFreeSpace returns false results on drives larger than 2 GB
+            return getFATClusterAndSectorSize(szDrive, uCluster, uSector);
+        }
+    } catch (...) {
+        ASSERT(0);
+    }
+
+    return (uCluster > 0);
+}
+
+bool
+getClusterSize(LPCTSTR szDrive, E_UINT32& uCluster)
+{
+    E_UINT32 uSector = 0;
+    return getClusterAndSectorSize(szDrive, uCluster, uSector);
+}
+
+bool
+getPartitionType(PARTITIONINFO& pi)
+{
+    TCHAR szFS[MAX_PATH];
+
+    if (GetVolumeInformation(pi.m_szDrive, NULL, 0, NULL, NULL, NULL, szFS, MAX_PATH)) {
+        if (_strcmpi(szFS, "FAT32") == 0) {
+            pi.m_fsType = fsFAT32;
+        } else if (_strcmpi(szFS, "FAT") == 0) {
+            pi.m_fsType = fsFAT;
+        } else if (_strcmpi(szFS, "NTFS") == 0) {
+            pi.m_fsType = fsNTFS;
+        } else {
+            pi.m_fsType = fsUnknown;
+        }
+        return true;
+    } else {
+        return false;
+    }
+}
+
+bool
+getPartitionInformation(CEraserContext *context, TCHAR cDrive)
+{
+    cDrive = (TCHAR)toupper(cDrive);
+
+    if (cDrive != context->m_piCurrent.m_szDrive[0] ||
+        context->m_piCurrent.m_bLastSuccess == false) {
+
+        // partition information wasn't cached
+        context->m_piCurrent.m_szDrive[0] = cDrive;
+
+        if (context->m_piCurrent.m_szDrive[0] < 'A' ||
+            context->m_piCurrent.m_szDrive[0] > 'Z') {
+
+            context->m_piCurrent.m_szDrive[0] = ' ';
+            context->m_piCurrent.m_bLastSuccess = false;
+        } else {
+            // determine file system type
+            context->m_piCurrent.m_bLastSuccess = getPartitionType(context->m_piCurrent);
+
+            // cluster and sector size, but not if erasing files and user
+            // doesn't want to touch cluster tip area
+
+            if (context->m_edtDataType != ERASER_DATA_FILES ||
+                bitSet(context->m_lsSettings.m_uItems, fileClusterTips)) {
+
+                if (!getClusterAndSectorSize(context->m_piCurrent.m_szDrive,
+                                             context->m_piCurrent.m_uCluster,
+                                             context->m_piCurrent.m_uSector)) {
+                    eraserAddError1(context, IDS_ERROR_CLUSTER, context->m_piCurrent.m_szDrive);
+                    context->m_piCurrent.m_bLastSuccess = false;
+                }
+            }
+        }
+    }
+
+    return context->m_piCurrent.m_bLastSuccess;
+}
+
+void
+countFilesOnDrive(CEraserContext *context, const CString& strDrive, E_UINT32& uFiles, E_UINT32& uFolders)
+{
+    // counts the amount of files on drive (including subfolders)
+    HANDLE          hFind;
+    WIN32_FIND_DATA wfdData;
+    CString         strRoot(strDrive);
+
+    // make sure that the directory name ends with a backslash
+
+    if (strRoot[strRoot.GetLength() - 1] != '\\') {
+        strRoot += "\\";
+    }
+
+    hFind = FindFirstFile((LPCTSTR) (strRoot + "*"), &wfdData);
+
+    if (hFind != INVALID_HANDLE_VALUE) {
+        try {
+            do {
+                if (eraserInternalTerminated(context)) {
+                    break;
+                }
+
+                if (bitSet(wfdData.dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY)) {
+                    // skip "." and ".."
+                    if (ISNT_SUBFOLDER(wfdData.cFileName)) {
+                        continue;
+                    }
+
+                    uFolders++;
+
+                    // recursive for subfolders
+                    countFilesOnDrive(context, (strRoot + wfdData.cFileName), uFiles, uFolders);
+                } else {
+                    uFiles++;
+                }
+            } while (FindNextFile(hFind, &wfdData));
+        } catch (...) {
+            ASSERT(0);
+        }
+
+        VERIFY(FindClose(hFind));
+    }
+}
+
+static bool
+wipeClusterTipsRecursive(CEraserContext *context, SFCISFILEPROTECTED pSfcIsFileProtected)
+{
+    // wipes unused cluster tips of each file on the drive given by context->m_strData
+
+    // the cluster size must have been set before calling this function
+    if (context->m_piCurrent.m_uCluster == 0) {
+        return false;
+    }
+
+    HANDLE hFind;
+    WIN32_FIND_DATA wfdData;
+    bool bCompleted = true;
+    CString strDirectory = context->m_strData;
+
+    // the directory name must end with a backslash
+    if (strDirectory[strDirectory.GetLength() - 1] != '\\') {
+        strDirectory += "\\";
+    }
+
+    hFind = FindFirstFile((LPCTSTR) (strDirectory + "*"), &wfdData);
+
+    if (hFind != INVALID_HANDLE_VALUE) {
+        WCHAR    szWideName[MAX_PATH];
+        CString  strFile;
+        E_UINT32 uAttributes;
+        E_UINT64 ulTotalSize;
+        FILETIME ftCreation, ftLastAccess, ftLastWrite;
+        bool     bSuccess;
+        bool     bIgnoreFile;
+
+        do {
+            if (eraserInternalTerminated(context)) {
+                bCompleted = false;
+                break;
+            }
+
+            if (bitSet(wfdData.dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY)) {
+                // skip "." and ".."
+                if (ISNT_SUBFOLDER(wfdData.cFileName)) {
+                    continue;
+                }
+                eraserSafeAssign(context, context->m_strData, strDirectory + wfdData.cFileName);
+
+                // recursive for subfolders
+                eraserBool(bCompleted, wipeClusterTipsRecursive(context, pSfcIsFileProtected));
+            } else {
+                // wipe slack space on the file
+                strFile = strDirectory + wfdData.cFileName;
+                eraserSafeAssign(context, context->m_strData, strFile);
+
+                bIgnoreFile = false;
+
+                // System File Protection - use only for Windows 2000 and later
+                if (isWindowsNT && pSfcIsFileProtected) {
+                    try {
+                        asciiToUnicode((LPCSTR)strFile, (LPWSTR)szWideName);
+
+                        // we skip protected files to avoid confusing the user
+                        if (pSfcIsFileProtected(NULL, (LPCWSTR)szWideName)) {
+                            context->m_saFailed.Add(strFile + " (Protected File)");
+
+                            bIgnoreFile = true;
+                            bCompleted = false;
+                        }
+                    } catch (...) {
+                        ASSERT(0);
+                    }
+                }
+
+                // wanna skip other files? add the code here then...
+
+                if (!bIgnoreFile) {
+                    eraserBeginNotify(context);
+
+                    // save file attributes
+                    uAttributes = GetFileAttributes((LPCTSTR)strFile);
+
+                    // skip compressed (and encrypted) files as overwriting the cluster tips
+                    // on them (or even opening) causes fragmentation and is useless anyway
+                    bIgnoreFile = (isWindowsNT && uAttributes != (E_UINT32)-1 &&
+                                   (bitSet(uAttributes, FILE_ATTRIBUTE_COMPRESSED) ||
+                                    bitSet(uAttributes, FILE_ATTRIBUTE_ENCRYPTED)  ||
+                                    bitSet(uAttributes, FILE_ATTRIBUTE_SPARSE_FILE)));
+
+                    if (!bIgnoreFile) {
+                        // change file attributes temporarily
+                        SetFileAttributes((LPCTSTR)strFile, FILE_ATTRIBUTE_NORMAL);
+
+                        context->m_hFile = CreateFile((LPCTSTR)strFile,
+                                                      GENERIC_READ | GENERIC_WRITE,
+                                                      (context->m_uTestMode) ?
+                                                        FILE_SHARE_READ | FILE_SHARE_WRITE : 0,
+                                                      NULL, OPEN_EXISTING,
+                                                      FILE_FLAG_WRITE_THROUGH,
+                                                      NULL);
+
+                        bSuccess = (context->m_hFile != INVALID_HANDLE_VALUE);
+
+                        if (bSuccess) {
+                            // save dates
+                            GetFileTime(context->m_hFile, &ftCreation, &ftLastAccess, &ftLastWrite);
+
+                            // file size
+                            context->m_uiFileSize.LowPart = GetFileSize(context->m_hFile, &context->m_uiFileSize.HighPart);
+
+                            if (context->m_uiFileSize.LowPart == (E_UINT32)-1 && GetLastError() != NO_ERROR) {
+                                bSuccess = false;
+                            } else {
+                                ulTotalSize = fileSizeToArea(context, context->m_uiFileSize.QuadPart);
+
+                                // continue if there is something to overwrite
+                                if (ulTotalSize > context->m_uiFileSize.QuadPart) {
+                                    context->m_uiFileStart.QuadPart = context->m_uiFileSize.QuadPart;
+                                    context->m_uiFileSize.QuadPart = ulTotalSize - context->m_uiFileSize.QuadPart;
+
+                                    context->m_uClusterSpace = context->m_uiFileSize.LowPart;
+
+                                    try {
+                                        // overwrite
+                                        bSuccess = context->m_lpmMethod->m_pwfFunction(context);
+                                    } catch (...) {
+                                        bSuccess = false;
+                                    }
+
+                                    // restore size
+                                    SetFilePointer(context->m_hFile, context->m_uiFileStart.LowPart,
+                                                   (LPLONG)&context->m_uiFileStart.HighPart, FILE_BEGIN);
+                                    SetEndOfFile(context->m_hFile);
+                                }
+                            }
+
+                            // restore dates
+                            SetFileTime(context->m_hFile, &ftCreation, &ftLastAccess, &ftLastWrite);
+                            CloseHandle(context->m_hFile);
+                        }
+
+                        // restore attributes
+                        SetFileAttributes((LPCTSTR)strFile, uAttributes);
+
+                        if (!bSuccess) {
+                            context->m_saFailed.Add(strFile);
+                            bCompleted = false;
+                        }
+                    }
+                }
+
+                // next file
+                context->m_uProgressWipedFiles++;
+
+                // set progress
+                eraserSafeAssign(context, context->m_uProgressPercent,
+                    (E_UINT8)((context->m_uProgressWipedFiles * 100) / context->m_uProgressFiles));
+                setTotalProgress(context);
+                eraserUpdateNotify(context);
+            }
+        } while (FindNextFile(hFind, &wfdData));
+
+        VERIFY(FindClose(hFind));
+    }
+
+    return bCompleted;
+}
+
+bool
+wipeClusterTips(CEraserContext *context)
+{
+    bool               bReturn = false;
+    SFCISFILEPROTECTED pSfcIsFileProtected = 0;
+    HINSTANCE          hInst = AfxLoadLibrary(ERASER_MODULENAME_SFC);
+
+    if (hInst != NULL) {
+        pSfcIsFileProtected = (SFCISFILEPROTECTED)GetProcAddress(hInst,
+                                    ERASER_FUNCTIONNAME_SFCISFILEPROTECTED);
+    }
+
+    // reset progress
+    context->m_uProgressWipedFiles = 0;
+
+    try {
+        bReturn = wipeClusterTipsRecursive(context, pSfcIsFileProtected);
+    } catch (CException *e) {
+        handleException(e, context);
+        bReturn = false;
+    }
+
+    if (hInst != NULL) {
+        AfxFreeLibrary(hInst);
+    }
+
+    return bReturn;
+}
+
+
+bool
+wipeFreeSpace(CEraserContext *context)
+{
+    CString strFolder;
+
+    try {
+        strFolder.Format("%s%s", context->m_piCurrent.m_szDrive, ERASER_TEMP_DIRECTORY);
+
+        // remove possibly existing folder
+        eraserRemoveFolder((LPVOID)(LPCTSTR)strFolder, (E_UINT16)strFolder.GetLength(),
+                           ERASER_REMOVE_RECURSIVELY);
+
+        // create temporary directory for temporary files
+        if (CreateDirectory((LPCTSTR)strFolder, NULL)) {
+            bool bResult = false;
+
+            try {
+                // make sure NTFS folder isn't compressed
+                uncompressFolder((LPCTSTR)strFolder);
+
+                bResult = eraserOK(eraserGetFreeDiskSpace((LPVOID)context->m_piCurrent.m_szDrive,
+                                   (E_UINT16)lstrlen(context->m_piCurrent.m_szDrive),
+                                   &context->m_uiFileSize.QuadPart));
+
+                if (bResult) {
+                    CString  strTempFile;
+                    TCHAR    szFileName[uShortFileNameLength + 1];
+                    E_UINT32 uFileSize = (E_UINT32)fileSizeToArea(context, ERASER_MAX_FILESIZE);
+                    E_UINT32 uFiles;
+                    E_UINT32 uAccessFlags = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING;
+
+                    // calculate the amount of fixed size files needed
+                    if (context->m_uiFileSize.QuadPart > (E_UINT64)uFileSize) {
+                        uFiles = (E_UINT32)(context->m_uiFileSize.QuadPart / (E_UINT64)uFileSize);
+                    } else {
+                        uFiles = 1;
+                    }
+
+                    // disable "Low Disk Space Notification" - Q188074, I am not so
+                    // convinced this works as advertized...
+                    E_UINT32 uWarningValue =
+                        disableLowDiskSpaceNotification(context->m_piCurrent.m_szDrive[0]);
+
+                    // show continuous progress info as if we were wiping only one file
+                    eraserProgressStartEstimate(context, context->m_uiFileSize.QuadPart);
+
+                    // set file size
+                    context->m_uiFileStart.QuadPart = 0;
+                    context->m_uiFileSize.QuadPart = uFileSize;
+                    context->m_uClusterSpace = 0;
+
+                    for (E_UINT32 uCurrent = 1; uCurrent <= uFiles; uCurrent++) {
+                        if (eraserInternalTerminated(context)) {
+                            bResult = false;
+                            break;
+                        }
+
+                        createRandomShortFileName(szFileName, (E_UINT16)uCurrent);
+                        strTempFile.Format("%s\\%s", strFolder, szFileName);
+
+                        // cannot disable buffering for the last file, its size may not be sector aligned
+                        if (uCurrent == uFiles) {
+                            uAccessFlags = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH;
+                        }
+
+                        context->m_hFile = CreateFile(strTempFile,
+                                                     GENERIC_WRITE, (context->m_uTestMode) ?
+                                                        FILE_SHARE_READ | FILE_SHARE_WRITE : 0,
+                                                     NULL, OPEN_ALWAYS, uAccessFlags, NULL);
+
+                        if (context->m_hFile != INVALID_HANDLE_VALUE) {
+                            // the size of the last file is the amount of space available
+                            try {
+                                if (uCurrent == uFiles) {
+                                    if (eraserOK(eraserGetFreeDiskSpace((LPVOID)context->m_piCurrent.m_szDrive,
+                                            (E_UINT16)lstrlen(context->m_piCurrent.m_szDrive),
+                                            &context->m_uiFileSize.QuadPart))) {
+
+                                        context->m_uProgressSize = UInt32x32To64((uFiles - 1), uFileSize) +
+                                                                   context->m_uiFileSize.QuadPart;
+
+                                        // set end of file
+                                        SetFilePointer(context->m_hFile, context->m_uiFileSize.LowPart,
+                                                       (LPLONG)&context->m_uiFileSize.HighPart, FILE_BEGIN);
+                                        SetEndOfFile(context->m_hFile);
+
+                                        // overwrite
+                                        bResult = context->m_lpmMethod->m_pwfFunction(context);
+                                    } else {
+                                        bResult = false;
+                                        eraserAddError1(context, IDS_ERROR_FREESPACE,
+                                            (LPCTSTR)context->m_piCurrent.m_szDrive);
+                                        context->m_saFailed.Add(context->m_strData);
+                                    }
+                                } else {
+                                    // overwrite
+                                    bResult = context->m_lpmMethod->m_pwfFunction(context);
+                                }
+                            } catch (CException *e) {
+                                handleException(e, context);
+                                bResult = false;
+                            }
+
+                            resetDate(context->m_hFile);
+                            CloseHandle(context->m_hFile);
+
+                            // don't add an error to the list if we were terminated
+                            if (!bResult && !eraserInternalTerminated(context)) {
+                                context->m_saFailed.Add(strTempFile);
+                            }
+                        } else {
+                            eraserAddError(context, IDS_ERROR_TEMPFILE);
+                            bResult = false;
+                        }
+
+                        // if something failed, give up
+                        if (!bResult) {
+                            break;
+                        }
+                    }
+
+                    // wipe unused space from MFT if an NTFS drive
+                    if (bResult && isWindowsNT && isFileSystemNTFS(context->m_piCurrent)) {
+                        increaseTotalProgressPercent(context);
+                        eraserBool(bResult, wipeMFTRecords(context));
+                    }
+
+                    // restore the "Low Disk Space Notification" value
+                    restoreLowDiskSpaceNotification(uWarningValue);
+                } else {
+                    eraserAddError1(context, IDS_ERROR_FREESPACE,
+                                    (LPCTSTR)context->m_piCurrent.m_szDrive);
+                    context->m_saFailed.Add(context->m_strData);
+                }
+            } catch (CException *e) {
+                handleException(e, context);
+                bResult = false;
+            }
+
+            // remove temporary directory and set error if failed
+            if (eraserError(eraserRemoveFolder((LPVOID)(LPCTSTR)strFolder,
+                    (E_UINT16)strFolder.GetLength(), ERASER_REMOVE_RECURSIVELY))) {
+
+                eraserAddError1(context, IDS_ERROR_DIRECTORY_REMOVE,
+                                (LPCTSTR)context->m_piCurrent.m_szDrive);
+                context->m_saFailed.Add(strFolder);
+                bResult = false;
+            }
+
+            return bResult;
+        } else {
+            eraserAddError1(context, IDS_ERROR_DIRECTORY,
+                            (LPCTSTR)context->m_piCurrent.m_szDrive);
+            context->m_saFailed.Add(context->m_strData);
+        }
+    } catch (CException *e) {
+        handleException(e, context);
+    }
+
+    return false;
+}
Index: /trunk/EraserDll/Common.h
===================================================================
--- /trunk/EraserDll/Common.h	(revision 4)
+++ /trunk/EraserDll/Common.h	(revision 4)
@@ -0,0 +1,270 @@
+// Common.h
+//
+// Eraser. Secure data removal. For Windows.
+// Copyright © 1997-2001  Sami Tolvanen (sami@tolvanen.com).
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#ifndef COMMON_H
+#define COMMON_H
+
+// global variable definition
+//
+#ifdef GLOBAL_VARIABLES_HERE
+    #define GLOBALVAR
+    #define GLOBALINIT1(x)    (x)
+    #define GLOBALINIT2(x, y) (x, y)
+#else
+    #define GLOBALVAR extern
+    #define GLOBALINIT1(x)
+    #define GLOBALINIT2(x, y)
+#endif
+
+#include "random.h"
+#include "eraserdllinternal.h"
+// the context array
+//
+GLOBALVAR CEraserContext *eraserContextArray[ERASER_MAX_CONTEXT + 1];
+// this is so the library can be accessed from multiple threads
+GLOBALVAR CCriticalSection csContextArray;
+
+// helpers for context access control
+#define eraserContextArrayAccess() \
+    eraserTraceLock("eraserContextArrayAccess\n"); \
+    CSingleLock sl(&csContextArray, TRUE)
+#define eraserContextArrayRelease() \
+    eraserTraceLock("eraserContextArrayRelease\n"); \
+    sl.Unlock()
+#define eraserContextArrayRelock() \
+    eraserTraceLock("eraserContextArrayRelock\n"); \
+    sl.Lock()
+
+// initialization control
+//
+GLOBALVAR CCriticalSection csReferenceCount;
+GLOBALVAR E_UINT16 uReferenceCount GLOBALINIT1(0);
+GLOBALVAR CEvent evLibraryInitialized GLOBALINIT2(FALSE, TRUE);
+
+// helpers
+#define eraserIsLibraryInit() \
+    (WaitForSingleObject(evLibraryInitialized, 0) == WAIT_OBJECT_0)
+
+#define eraserLibraryInit() \
+    evLibraryInitialized.SetEvent(); \
+    csReferenceCount.Lock(); \
+    uReferenceCount++; \
+    csReferenceCount.Unlock()
+
+#define eraserLibraryUninit() \
+    csReferenceCount.Lock(); \
+    if (uReferenceCount > 0) { \
+        uReferenceCount--; \
+    } \
+    if (uReferenceCount == 0) { \
+        evLibraryInitialized.ResetEvent(); \
+    } \
+    csReferenceCount.Unlock()
+#define eraserLibraryUnlock() \
+    csReferenceCount.Lock(); \
+    uReferenceCount = 0; \
+    evLibraryInitialized.ResetEvent(); \
+    csReferenceCount.Unlock()
+
+
+// other global variables
+//
+GLOBALVAR bool isWindowsNT;
+bool ERASER_API IsWindowsNT();
+
+const E_UINT16 uExceptionBufferSize = 127;
+GLOBALVAR TCHAR szExceptionBuffer[uExceptionBufferSize];
+
+
+// safe characters for filenames (excluded some that are not that so common)
+//
+const E_UINT16 ERASER_SAFEARRAY_SIZE = 36;
+const LPCTSTR ERASER_SAFEARRAY = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+inline void createRandomFileName(LPTSTR szFileName, E_UINT16 uNameLength, E_UINT16 uExtLength, E_UINT16 uCounter)
+{
+    // szFileName needs to be at least (uNameLength + 1 + uExtLength + 1) bytes long
+    try {
+        E_UINT32 uLength = uNameLength;
+
+        if (uExtLength > 0) {
+            uLength += uExtLength + 1;
+        }
+
+        if (uLength >= MAX_PATH) {
+            uLength = MAX_PATH - 1;
+        }
+
+        E_UINT8 uRandomArray[MAX_PATH];
+        isaacFill(uRandomArray, MAX_PATH);
+
+        for (E_UINT32 uIndex = 0; uIndex < uLength; uIndex++) {
+            szFileName[uIndex] = ERASER_SAFEARRAY[uRandomArray[uIndex] % ERASER_SAFEARRAY_SIZE];
+        }
+
+        ZeroMemory(uRandomArray, MAX_PATH);
+
+        if (uCounter > 0 && uNameLength >= 4) {
+            _snprintf(&szFileName[uNameLength - 4], 4, "%04X", uCounter);
+        }
+
+        if (uExtLength > 0) {
+            szFileName[uNameLength] = '.';
+        }
+
+        szFileName[uLength] = 0;
+    } catch (...) {
+        ASSERT(0);
+    }
+}
+
+const E_UINT16 uShortFileNameLength = 8 + 1 + 3;
+#define createRandomShortFileName(szFileName, uCounter) \
+    createRandomFileName((szFileName), 8, 3, (uCounter))
+
+
+// common helpers for all wipe functions to handle notification and
+// statistics
+//
+inline void
+countTotalProgressTasks(CEraserContext *context)
+{
+    // erasing unused disk space is divided to three steps when
+    // it comes to showing total progress
+
+    context->m_uProgressTasks = 0;
+    if (bitSet(context->m_lsSettings.m_uItems, diskClusterTips)) {
+        context->m_uProgressTasks++;
+    }
+    if (bitSet(context->m_lsSettings.m_uItems, diskFreeSpace)) {
+        context->m_uProgressTasks++;
+        if (isWindowsNT && isFileSystemNTFS(context->m_piCurrent)) {  // MFT records
+            context->m_uProgressTasks++;
+        }
+    }
+    if (bitSet(context->m_lsSettings.m_uItems, diskDirEntries)) {
+        context->m_uProgressTasks++;
+    }
+    if (context->m_uProgressTasks < 1) {
+        context->m_uProgressTasks = 1;
+    }
+}
+
+#pragma warning(disable : 4244)
+
+inline void
+increaseTotalProgressPercent(CEraserContext *context)
+{
+    // one task has been completed, increase m_uProgressTaskPercent
+    if (context->m_uProgressTasks > 1) {
+        context->m_uProgressTaskPercent += 100 / context->m_uProgressTasks;
+    }
+}
+
+#pragma warning(default : 4244)
+
+inline void
+setTotalProgress(CEraserContext *context)
+{
+    eraserContextAccess(context);
+
+    if (context->m_edtDataType == ERASER_DATA_FILES) {
+        context->m_uProgressTotalPercent =
+            (E_UINT8)( ((context->m_uProgressWipedFiles * 100) / context->m_uProgressFiles) +
+                       (context->m_uProgressPercent / context->m_uProgressFiles));
+    } else {
+        context->m_uProgressTotalPercent =
+            (E_UINT8)( ((context->m_uProgressWipedDrives * 100 + context->m_uProgressTaskPercent) /
+                            context->m_uProgressDrives) +
+                       (context->m_uProgressPercent / (context->m_uProgressTasks * context->m_uProgressDrives)));
+    }
+}
+
+inline void
+postStartNotification(CEraserContext *context)
+{
+    // send update only when starting the overwriting
+    if (!bitSet(context->m_uProgressFlags, progressCustom) && context->m_uProgressWiped == 0) {
+        eraserBeginNotify(context);
+    }
+}
+
+inline void
+postUpdateNotification(CEraserContext *context, E_UINT16 passes)
+{
+    if (!bitSet(context->m_uProgressFlags, progressCustom)) {
+        eraserContextAccess(context);
+
+        context->m_uProgressPercent =
+            (E_UINT8)(((E_UINT64)(context->m_uProgressWiped * 100)) /
+                     ((E_UINT64)(context->m_uProgressSize * passes)));
+
+        setTotalProgress(context);
+
+        E_UINT32 uTickCount = GetTickCount();
+        if (uTickCount > context->m_uProgressStartTime) {
+            E_UINT64 uSpeed =
+                context->m_uProgressWiped / (E_UINT64)(uTickCount - context->m_uProgressStartTime);
+
+            if (uSpeed > 0) {
+                context->m_uProgressTimeLeft =
+                    (E_UINT32)(((context->m_uProgressSize * passes) - context->m_uProgressWiped) /
+                             (uSpeed * 1000));
+            } else {
+                context->m_uProgressTimeLeft = 0;
+            }
+        }
+
+        eraserUpdateNotifyNoAccess(context);
+    }
+}
+
+inline void
+setEndStatistics(CEraserContext *context, E_UINT64& uWiped, E_UINT32& uPrevTime)
+{
+    E_UINT32 uTickCount = GetTickCount();
+
+    // wiped area
+    context->m_uStatWiped += uWiped;
+
+    // if the given area was completely overwritten at least once
+    if (uWiped >= context->m_uiFileSize.QuadPart) {
+        context->m_uStatErasedArea += context->m_uiFileSize.QuadPart;
+        context->m_uStatTips += context->m_uClusterSpace;
+    } else {
+        // the whole area was not even once completely overwritten
+        context->m_uStatErasedArea += uWiped;
+
+        if (context->m_uClusterSpace > 0 &&
+            uWiped > (context->m_uiFileSize.QuadPart - context->m_uClusterSpace)) {
+            // this is how much of the cluster tips actually was overwritten
+            context->m_uStatTips += context->m_uiFileSize.QuadPart -
+                                    context->m_uClusterSpace;
+        }
+    }
+
+    // time
+    if (uTickCount > uPrevTime) {
+        context->m_uStatTime += (uTickCount - uPrevTime);
+    }
+}
+
+
+#endif
Index: /trunk/EraserDll/OptionPages.h
===================================================================
--- /trunk/EraserDll/OptionPages.h	(revision 4)
+++ /trunk/EraserDll/OptionPages.h	(revision 4)
@@ -0,0 +1,165 @@
+// OptionPages.h
+//
+// Eraser. Secure data removal. For Windows.
+// Copyright © 1997-2001  Sami Tolvanen (sami@tolvanen.com).
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#ifndef __OPTIONPAGES_H__
+#define __OPTIONPAGES_H__
+
+#include "../shared/FlatListCtrl.h"
+
+/////////////////////////////////////////////////////////////////////////////
+// COptionsForFiles dialog
+
+class COptionsForFreeSpace;
+
+class COptionsForFilesData;
+struct LibrarySettings;
+
+class  ERASER_API COptionsForFiles : public CPropertyPage
+{
+    DECLARE_DYNCREATE(COptionsForFiles)
+	
+
+// Construction
+public:
+    void EnableButtons(BYTE);
+    COptionsForFiles();
+    ~COptionsForFiles();
+
+    void UpdateList();
+
+private:
+	COptionsForFilesData* m_pData;
+public:
+	static COptionsForFiles* create();
+	LibrarySettings* GetLibSettings();
+	void SetLibSettings(LibrarySettings* val);
+	COptionsForFreeSpace* GetFreeSpaceOpt();
+	void SetFreeSpaceOpt(COptionsForFreeSpace* val);
+	BYTE GetSelectedMethodId();
+	void SetSelectedMethodId(BYTE val);
+	int GetSelectedMethod();
+	void SetSelectedMethod(int val);
+	CFlatListCtrl& GetMethodList();
+	CString& GetSelectedStr();
+	void SetSelectedStr(CString val);
+	BOOL& GetFileClusterTips();
+	void SetFileClusterTips(BOOL val);
+	BOOL& GetFileNames();
+	void SetFileNames(BOOL val);
+	BOOL& GetFileAltDataStreams();
+	void SetFileAltDataStreams(BOOL val);
+
+    
+
+// Dialog Data
+    //{{AFX_DATA(COptionsForFiles)
+	
+	//}}AFX_DATA
+
+
+// Overrides
+    // ClassWizard generate virtual function overrides
+    //{{AFX_VIRTUAL(COptionsForFiles)
+    public:
+    virtual void OnOK();
+    protected:
+    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
+    //}}AFX_VIRTUAL
+
+// Implementation
+protected:
+
+    // Generated message map functions
+    //{{AFX_MSG(COptionsForFiles)
+    virtual BOOL OnInitDialog();
+	virtual BOOL OnSetActive();
+	
+/*	virtual BOOL OnKillActive( );
+*/
+    afx_msg void OnButtonDelete();
+    afx_msg void OnButtonEdit();
+    afx_msg void OnButtonNew();
+    afx_msg void OnItemchangedListMethod(NMHDR* pNMHDR, LRESULT* pResult);
+	afx_msg void OnDblclkListMethod(NMHDR* pNMHDR, LRESULT* pResult);
+	//}}AFX_MSG
+    DECLARE_MESSAGE_MAP()
+
+};
+
+
+/////////////////////////////////////////////////////////////////////////////
+// COptionsForFreeSpace dialog
+
+class COptionsForFreeSpace : public CPropertyPage
+{
+    DECLARE_DYNCREATE(COptionsForFreeSpace)
+
+// Construction
+public:
+    void EnableButtons(BYTE);
+    COptionsForFreeSpace();
+    ~COptionsForFreeSpace();
+
+    void UpdateList();
+
+    LibrarySettings *m_plsSettings;
+
+    COptionsForFiles *m_ppgFiles;
+    BYTE m_nSelectedMethodID;
+    int m_nSelectedMethod;
+
+// Dialog Data
+    //{{AFX_DATA(COptionsForFreeSpace)    
+	//enum { IDD = IDD_PAGE_FREESPACE };
+    CFlatListCtrl   m_lcMethod;
+    BOOL    m_bClusterTips;
+    BOOL    m_bDirectoryEntries;
+    BOOL    m_bFreeSpace;
+    CString m_strSelected;
+    //}}AFX_DATA
+
+// Overrides
+    // ClassWizard generate virtual function overrides
+    //{{AFX_VIRTUAL(COptionsForFreeSpace)
+    public:
+    virtual void OnOK();
+    protected:
+    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
+    //}}AFX_VIRTUAL
+
+// Implementation
+protected:
+
+    // Generated message map functions
+    //{{AFX_MSG(COptionsForFreeSpace)
+    virtual BOOL OnInitDialog();
+    afx_msg void OnButtonEdit();
+    afx_msg void OnButtonNew();
+    afx_msg void OnButtonDelete();
+    afx_msg void OnItemchangedListMethod(NMHDR* pNMHDR, LRESULT* pResult);
+	afx_msg void OnDblclkListMethod(NMHDR* pNMHDR, LRESULT* pResult);
+	//}}AFX_MSG
+	
+    DECLARE_MESSAGE_MAP()
+};
+
+
+
+#endif // __OPTIONPAGES_H__
Index: /trunk/EraserDll/Options.h
===================================================================
--- /trunk/EraserDll/Options.h	(revision 4)
+++ /trunk/EraserDll/Options.h	(revision 4)
@@ -0,0 +1,31 @@
+// Options.h
+//
+// Eraser. Secure data removal. For Windows.
+// Copyright © 1997-2001  Sami Tolvanen (sami@tolvanen.com).
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#ifndef OPTIONS_H
+#define OPTIONS_H
+
+void
+ERASER_API setLibraryDefaults(LibrarySettings *);
+bool
+ERASER_API loadLibrarySettings(LibrarySettings *);
+bool
+ERASER_API saveLibrarySettings(LibrarySettings *);
+
+#endif
Index: /trunk/EraserDll/ReportDialog.h
===================================================================
--- /trunk/EraserDll/ReportDialog.h	(revision 4)
+++ /trunk/EraserDll/ReportDialog.h	(revision 4)
@@ -0,0 +1,68 @@
+// ReportDialog.h
+//
+// Eraser. Secure data removal. For Windows.
+// Copyright © 1997-2001  Sami Tolvanen (sami@tolvanen.com).
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#if !defined(AFX_REPORTDIALOG_H__E04E0B5A_267B_48B4_9EFF_A4321F890EC3__INCLUDED_)
+#define AFX_REPORTDIALOG_H__E04E0B5A_267B_48B4_9EFF_A4321F890EC3__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+/////////////////////////////////////////////////////////////////////////////
+// CReportDialog dialog
+
+class CReportDialog : public CDialog
+{
+// Construction
+public:
+	CReportDialog(CWnd* pParent = NULL);   // standard constructor
+    CStringArray *m_pstraErrorArray;
+
+// Dialog Data
+	//{{AFX_DATA(CReportDialog)
+	enum { IDD = IDD_DIALOG_REPORT };
+	CListCtrl	m_listErrors;
+	CString	m_strStatistics;
+	CString	m_strCompletion;
+	//}}AFX_DATA
+
+
+// Overrides
+	// ClassWizard generated virtual function overrides
+	//{{AFX_VIRTUAL(CReportDialog)
+	protected:
+	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
+	//}}AFX_VIRTUAL
+
+// Implementation
+protected:
+
+	// Generated message map functions
+	//{{AFX_MSG(CReportDialog)
+	afx_msg void OnSaveAs();
+	virtual BOOL OnInitDialog();
+	//}}AFX_MSG
+	DECLARE_MESSAGE_MAP()
+};
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_REPORTDIALOG_H__E04E0B5A_267B_48B4_9EFF_A4321F890EC3__INCLUDED_)
Index: /trunk/EraserDll/SecManDlg.h
===================================================================
--- /trunk/EraserDll/SecManDlg.h	(revision 4)
+++ /trunk/EraserDll/SecManDlg.h	(revision 4)
@@ -0,0 +1,46 @@
+#pragma once
+
+
+#include "resource.h"
+class CSecManDlg : public CDialog
+{
+	DECLARE_DYNAMIC(CSecManDlg)
+
+public:
+	CSecManDlg(CWnd* pParent = NULL);   // standard constructor
+	virtual ~CSecManDlg();
+
+// Dialog Data
+	enum { IDD = IDD_DIALOG_SEC_MAN };
+	enum Mode{CHECKUP = 0, SETUP =1};
+
+	inline void SetMode(Mode m)
+	{
+		m_mMode = m;
+	}
+	inline Mode GetMode() const
+	{
+		return m_mMode;
+	}
+	inline const CString& GetSecret() const
+	{
+		return m_Password;
+	}
+	inline void Clear()
+	{
+		m_Password = "";
+		m_PasswordConfirm = "";
+	}
+protected:
+	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
+
+	DECLARE_MESSAGE_MAP()
+private:
+	CString m_Password;
+	CString m_PasswordConfirm;
+	Mode m_mMode;
+protected:
+	virtual void OnOK();
+public:
+	virtual BOOL OnInitDialog();
+};
Index: /trunk/EraserDll/SecurityManager.cpp
===================================================================
--- /trunk/EraserDll/SecurityManager.cpp	(revision 4)
+++ /trunk/EraserDll/SecurityManager.cpp	(revision 4)
@@ -0,0 +1,360 @@
+// SecurityManager.cpp
+//
+// Eraser. Secure data removal. For Windows.
+// Copyright © 1997-2001  Sami Tolvanen (sami@tolvanen.com).
+// Copyright © 2001-2006  Garrett Trant (support@heidi.ie).
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+#include "stdafx.h"
+#include "SecurityManager.h"
+#include "SecManDlg.h"
+
+#include <vector>
+#include <atlbase.h>
+#include <atlcrypt.h>
+#include <atlsecurity.h>
+#define REG_PROTECT_KEY "Software\\Heidi Computers Ltd\\Eraser\\PROTECT"
+#define REG_PRODUCT_KEY "Software\\Heidi Computers Ltd\\Eraser"
+
+#define PROTECTION "protection"
+#define SECRET "sec"
+
+#pragma comment( lib, "Crypt32" )
+
+enum
+{
+	PROTECTION_ON = 1, PROTECTION_OFF = 0
+};
+
+__declspec(dllexport) bool no_registry;
+
+CSecurityManager::CSecurityManager(void)
+{
+}
+
+CSecurityManager::~CSecurityManager(void)
+{
+}
+static void init_sa(CSecurityAttributes& sa)
+{
+	TCHAR tcUser[1024];
+	DWORD dwSize = sizeof (tcUser);
+	if (FALSE == GetUserName(tcUser, &dwSize))
+	{
+		throw std::runtime_error("User detection error");
+	}
+
+	CDacl ac;	
+	ac.AddAllowedAce(CSid(tcUser), MAXIMUM_ALLOWED|GENERIC_ALL);
+	ac.AddAllowedAce(Sids::Users(), GENERIC_READ);
+	ac.AddAllowedAce(Sids::World(), GENERIC_READ);
+	ac.AddAllowedAce(Sids::Admins(), GENERIC_ALL);
+
+
+	CSecurityDesc sd;
+	sd.SetDacl(ac);	
+	sa.Set(sd);
+
+}
+void 
+CSecurityManager::Protect(const char* szSecret )
+{
+	extern bool no_registry;
+	if (no_registry)
+		return;
+
+	CRegKey protect;		
+	SetLastError(0);
+	DWORD dwErrorCode = 0;
+
+	if (ERROR_SUCCESS != protect.Create(HKEY_LOCAL_MACHINE, REG_PRODUCT_KEY ))
+		throw std::runtime_error("Unable create key");
+
+
+	CSecurityAttributes sa;
+	init_sa(sa);
+
+	dwErrorCode = protect.Create(HKEY_LOCAL_MACHINE, 
+		REG_PROTECT_KEY
+		, REG_NONE
+		, REG_OPTION_NON_VOLATILE
+		, KEY_READ | KEY_WRITE
+		, &sa);
+
+
+	if (ERROR_SUCCESS != dwErrorCode)
+	{
+		if (ERROR_ACCESS_DENIED == dwErrorCode)
+			throw std::runtime_error("Access denied");			
+		throw std::runtime_error("Unable create key");
+	}
+
+
+	DATA_BLOB data_in;
+	data_in.cbData = static_cast<DWORD>(strlen(szSecret) + 1);
+	data_in.pbData = reinterpret_cast<BYTE*>(const_cast<LPTSTR>(szSecret));
+	CRYPTPROTECT_PROMPTSTRUCT promt;
+	ZeroMemory(&promt, sizeof(promt));
+	promt.cbSize = sizeof(promt);
+	promt.dwPromptFlags = 0;
+	DATA_BLOB data_out;
+	DATA_BLOB data_entropy = data_in;
+
+
+	if(!CryptProtectData(
+		&data_in,
+		L"Eraser's protection",// A description string. 
+		&data_entropy ,                               // Optional entropy
+
+		NULL,                               // Reserved.
+		&promt,                      // Pass a PromptStruct.
+		0,
+		&data_out))
+	{
+		throw std::runtime_error("Encryption error");
+	}
+
+	dwErrorCode = protect.SetBinaryValue(SECRET, data_out.pbData, data_out.cbData);
+
+	LocalFree(data_out.pbData);
+
+	if (ERROR_SUCCESS != dwErrorCode )
+	{
+
+		throw std::runtime_error("Unable set protection off");
+	}
+
+	protect.Close();
+
+}
+
+void 
+CSecurityManager::Unprotect()
+{
+	extern bool no_registry;
+	if (no_registry)
+		return;
+
+	CRegKey protect;
+
+	DWORD dwErrorCode = protect.Open(HKEY_LOCAL_MACHINE, REG_PRODUCT_KEY);
+	if (ERROR_SUCCESS != dwErrorCode )
+	{
+		if (ERROR_ACCESS_DENIED == dwErrorCode)
+			throw std::runtime_error("Access denied");	
+
+		return;
+	}
+
+	dwErrorCode = protect.DeleteSubKey("PROTECT");
+	/*
+	if (ERROR_SUCCESS != dwErrorCode )	
+	throw std::runtime_error("Unable to unprotect");	
+	*/
+}
+
+bool 
+CSecurityManager::Check(const char* szSecret )
+{
+	extern bool no_registry;
+	if (no_registry)
+		return true;
+
+	CRegKey protect;
+
+	DWORD dwErrorCode = protect.Open(HKEY_LOCAL_MACHINE, REG_PROTECT_KEY, KEY_READ);
+	if (ERROR_SUCCESS != dwErrorCode )
+	{
+		if (ERROR_ACCESS_DENIED == dwErrorCode )
+			throw std::runtime_error("Access denied");
+		return true;
+	}	
+
+	ULONG blob_len;
+	if (ERROR_SUCCESS != protect.QueryBinaryValue(SECRET, NULL, &blob_len))
+		throw std::runtime_error("No data");
+
+	std::vector<unsigned char> blob;
+	blob.resize(blob_len);	
+
+	if (ERROR_SUCCESS != protect.QueryBinaryValue(SECRET, &blob[0], &blob_len))
+		throw std::runtime_error("No data");
+
+	LPWSTR pDescrOut = NULL;
+
+	DATA_BLOB data_verify;
+	DATA_BLOB data_enc;
+	DATA_BLOB data_entropy;
+	data_entropy.cbData = static_cast<DWORD>(strlen(szSecret) + 1);
+	data_entropy.pbData = reinterpret_cast<BYTE*>(const_cast<LPTSTR>(szSecret));
+	data_enc.cbData = blob_len;
+	data_enc.pbData = reinterpret_cast<BYTE*>(&blob[0]);
+
+	CRYPTPROTECT_PROMPTSTRUCT promt;
+	ZeroMemory(&promt, sizeof(promt));
+	promt.cbSize = sizeof(promt);
+	promt.dwPromptFlags = 0;
+
+	if (!CryptUnprotectData(
+		&data_enc,
+		&pDescrOut,
+		&data_entropy,                 // Optional entropy
+		NULL,                 // Reserved
+		&promt,        // Optional PromptStruct
+		0,
+		&data_verify))
+	{
+
+		return false;
+	}
+	bool ret = (0 == memcmp(data_verify.pbData, szSecret, data_verify.cbData));
+	LocalFree(pDescrOut);
+	LocalFree(data_verify.pbData);
+	return ret;
+}
+bool
+CSecurityManager::IsProtected()
+{
+	extern bool no_registry;
+	if (no_registry)
+		return false;
+
+	CRegKey protect;
+
+	DWORD dwErrorCode = protect.Open(HKEY_LOCAL_MACHINE, REG_PROTECT_KEY, KEY_READ);
+	if (ERROR_SUCCESS != dwErrorCode )			
+		return ERROR_ACCESS_DENIED == dwErrorCode;		
+
+
+	ULONG blob_len(1);
+	dwErrorCode  = protect.QueryBinaryValue(SECRET, NULL, &blob_len);
+	if (ERROR_ACCESS_DENIED == dwErrorCode  )
+		return true;
+
+	return ERROR_SUCCESS == dwErrorCode;
+
+}
+
+bool CheckAccess(DWORD dwMaxError /*= 3*/)
+{
+
+	bool is_ok(false);
+	try
+	{
+		if (!CSecurityManager::IsProtected())	
+			return true;
+		AFX_MANAGE_STATE(AfxGetStaticModuleState( ))
+
+	
+		CSecManDlg dlg;
+		dlg.SetMode(CSecManDlg::CHECKUP);
+		for (DWORD  i = 0; i <dwMaxError;)
+		{
+			dlg.Clear();
+			if (IDOK  != dlg.DoModal())
+				return false;
+			
+			is_ok = CSecurityManager::Check(dlg.GetSecret());
+
+			if (is_ok)							
+				return true;
+			++i;						
+			AfxGetApp()->GetMainWnd()->MessageBox("Password incorrect", "Security error", MB_OK|MB_ICONERROR);
+		}
+	}
+	catch (const CAtlException& )
+	{
+		is_ok = false;
+	}
+	catch (CException* ee)
+	{
+		ee->ReportError();
+		ee->Delete();
+		is_ok = false;
+	}
+	catch (const std::exception& e)
+	{
+		AfxGetApp()->GetMainWnd()->MessageBox(e.what(), "Security error", MB_OK|MB_ICONERROR);
+		is_ok = false;
+	}
+	
+	return is_ok;
+}
+
+bool SetProtection()
+{
+	bool is_ok(false);
+	try
+	{	
+		if (!CheckAccess(1))
+			return false;
+
+		AFX_MANAGE_STATE(AfxGetStaticModuleState( ))
+
+		CSecManDlg dlg;
+		dlg.SetMode(CSecManDlg::SETUP);
+		if (IDOK  != dlg.DoModal())
+			return false;
+
+		CSecurityManager::Protect(dlg.GetSecret());
+		is_ok = true;
+	}
+	catch (const CAtlException& )
+	{
+		is_ok = false;
+	}
+	catch (CException* ee)
+	{
+		ee->ReportError();
+		ee->Delete();
+		is_ok = false;
+	}
+	catch (const std::exception& e)
+	{
+		AfxGetApp()->GetMainWnd()->MessageBox(e.what(), "Security error", MB_OK|MB_ICONERROR);
+		is_ok = false;
+	}
+	return is_ok;
+}
+
+bool ClearProtection()
+{
+	bool is_ok(false);
+	try
+	{
+		if (!CheckAccess(1))
+			return false;
+
+		CSecurityManager::Unprotect();
+		is_ok = true;
+	}
+	catch (const CAtlException& )
+	{
+		is_ok = false;
+	}
+	catch (CException* ee)
+	{
+		ee->ReportError();
+		ee->Delete();
+		is_ok = false;
+	}
+	catch (const std::exception& e)
+	{
+		AfxGetApp()->GetMainWnd()->MessageBox(e.what(), "Security error", MB_OK|MB_ICONERROR);
+		is_ok = false;
+	}
+	return is_ok;
+}
Index: /trunk/EraserDll/PassEditDlg.cpp
===================================================================
--- /trunk/EraserDll/PassEditDlg.cpp	(revision 4)
+++ /trunk/EraserDll/PassEditDlg.cpp	(revision 4)
@@ -0,0 +1,91 @@
+// PassEditDlg.cpp
+//
+// Eraser. Secure data removal. For Windows.
+// Copyright © 1997-2001  Sami Tolvanen (sami@tolvanen.com).
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#include "stdafx.h"
+#include "eraser.h"
+#include "EraserDll.h"
+#include "PassEditDlg.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CPassEditDlg dialog
+
+
+CPassEditDlg::CPassEditDlg(CWnd* pParent /*=NULL*/)
+    : CDialog(CPassEditDlg::IDD, pParent)
+{
+    //{{AFX_DATA_INIT(CPassEditDlg)
+    m_uPasses = 0;
+    //}}AFX_DATA_INIT
+    m_bIgnoreChange = true;
+}
+
+
+void CPassEditDlg::DoDataExchange(CDataExchange* pDX)
+{
+    CDialog::DoDataExchange(pDX);
+    //{{AFX_DATA_MAP(CPassEditDlg)
+    DDX_Control(pDX, IDC_SPIN_PASSES, m_spinPasses);
+    DDX_Text(pDX, IDC_EDIT_PASSES, m_uPasses);
+	//}}AFX_DATA_MAP
+}
+
+
+BEGIN_MESSAGE_MAP(CPassEditDlg, CDialog)
+    //{{AFX_MSG_MAP(CPassEditDlg)
+	ON_EN_CHANGE(IDC_EDIT_PASSES, OnChangeEditPasses)
+	//}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CPassEditDlg message handlers
+
+BOOL CPassEditDlg::OnInitDialog()
+{
+    m_bIgnoreChange = true;
+    CDialog::OnInitDialog();
+
+    m_spinPasses.SetRange32(1, PASSES_MAX);
+    m_spinPasses.SetPos((int)m_uPasses);
+
+    // the spin control fails to set the window text if m_uPasses
+    // is greater than (2^16)/2 - 1, so we'll have to help it...
+    CString strText;
+    strText.Format("%u", m_uPasses);
+    GetDlgItem(IDC_EDIT_PASSES)->SetWindowText((LPCTSTR)strText);
+
+    m_bIgnoreChange = false;
+    return TRUE;  // return TRUE unless you set the focus to a control
+                  // EXCEPTION: OCX Property Pages should return FALSE
+}
+
+void CPassEditDlg::OnChangeEditPasses()
+{
+    if (!m_bIgnoreChange)
+    {
+	    UpdateData();
+        GetDlgItem(IDOK)->EnableWindow(m_uPasses <= PASSES_MAX && m_uPasses >= 1);
+    }
+}
Index: /trunk/EraserDll/DOD.cpp
===================================================================
--- /trunk/EraserDll/DOD.cpp	(revision 4)
+++ /trunk/EraserDll/DOD.cpp	(revision 4)
@@ -0,0 +1,135 @@
+// DOD.cpp
+//
+// Implementation of US DoD 5220.22-M (aka NISPOM), Chapter 8,
+// Section 3, 8-306. Maintenance. Parts E, C and E (again) of
+// the Clearing and Sanitization Matrix.
+//
+// Eraser. Secure data removal. For Windows.
+// Copyright © 1997-2001  Sami Tolvanen (sami@tolvanen.com).
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#include "stdafx.h"
+#include "EraserDll.h"
+#include "Common.h"
+#include "DOD.h"
+
+const E_UINT32 DOD_RANDOM_PASSES = 3;
+
+bool
+wipeFileWithDoD(CEraserContext *context)
+{
+    LPPASS   passDOD    = context->m_lpmMethod->m_lpPasses;
+    E_UINT32 uStartTime = GetTickCount();
+    E_UINT32 uUsedSize  = 0;
+    E_UINT32 uSavedSize = 0;
+    E_UINT64 uLength    = 0;
+    E_UINT64 uWiped     = 0;
+    E_UINT32 uWritten   = 0;
+    E_UINT8  uRandomArray[DOD_RANDOM_PASSES];
+    bool     bCompleted = true;
+
+    // send the begin message only once
+    postStartNotification(context);
+
+    setBufferSize(context, uSavedSize);
+
+    // set passes 1, 4 and 5 to be random characters
+    isaacFill(uRandomArray, DOD_RANDOM_PASSES);
+
+    setPassOne(passDOD[0], (E_UINT16)uRandomArray[0]);
+    setPassOne(passDOD[3], (E_UINT16)uRandomArray[1]);
+    setPassOne(passDOD[4], (E_UINT16)uRandomArray[2]);
+
+    ZeroMemory(uRandomArray, DOD_RANDOM_PASSES);
+
+    // set passes 2 and 6 to be complements of 1 and 5
+    setPassOne(passDOD[1], (E_UINT16)(~(passDOD[0].byte1) & 0x00FF));
+    setPassOne(passDOD[5], (E_UINT16)(~(passDOD[4].byte1) & 0x00FF));
+
+    for (E_UINT16 uCurrentPass = 0; uCurrentPass < PASSES_DOD; uCurrentPass++) {
+        eraserSafeAssign(context, context->m_uProgressCurrentPass, (E_UINT16)(uCurrentPass + 1));
+
+        // start from the beginning again
+        SetFilePointer(context->m_hFile, context->m_uiFileStart.LowPart,
+                       (E_PINT32)&context->m_uiFileStart.HighPart, FILE_BEGIN);
+
+        uLength = context->m_uiFileSize.QuadPart;
+        uUsedSize = uSavedSize;
+
+        // fill buffer
+        fillPassData(context->m_puBuffer, uUsedSize, &passDOD[uCurrentPass]);
+
+        while (uLength > 0) {
+            // random data needs refilling
+            if (isRandomPass(passDOD[uCurrentPass])) {
+                isaacFill((E_PUINT8)context->m_puBuffer, uUsedSize);
+            }
+
+             // use the whole buffer as long as we can
+            if (uLength < (E_UINT64)uUsedSize) {
+                uUsedSize = (E_UINT32)uLength;
+            }
+
+            // completed if not terminated and write is successful
+            bCompleted = !eraserInternalTerminated(context) &&
+                         WriteFile(context->m_hFile, context->m_puBuffer,
+                                   uUsedSize, &uWritten, NULL) &&
+                         (uUsedSize == uWritten);
+
+            // flush to disk
+            FlushFileBuffers(context->m_hFile);
+
+            // if not completed - stop!
+            if (!bCompleted) {
+                break;
+            }
+
+            // set statistics
+            context->m_uProgressWiped += (E_UINT64)uUsedSize;
+            uWiped += (E_UINT64)uUsedSize;
+
+            // how much left to go?
+            uLength -= (E_UINT64)uUsedSize;
+
+            // send update to window
+            postUpdateNotification(context, PASSES_DOD);
+        }
+
+        if (context->m_uTestMode && !eraserInternalTerminated(context)) {
+            // pause, so the results can be examined
+            context->m_evTestContinue.ResetEvent();
+            eraserTestPausedNotify(context);
+            WaitForSingleObject(context->m_evTestContinue, INFINITE);
+        }
+
+        if (!bCompleted) {
+            break;
+        }
+    }
+
+    // set statistics
+    setEndStatistics(context, uWiped, uStartTime);
+
+    // clear pass array to prevent spying...
+    setPassOne(passDOD[0], 0);
+    setPassOne(passDOD[1], 0);
+    setPassOne(passDOD[3], 0);
+    setPassOne(passDOD[4], 0);
+    setPassOne(passDOD[5], 0);
+
+    return bCompleted;
+}
Index: /trunk/EraserDll/Pass.cpp
===================================================================
--- /trunk/EraserDll/Pass.cpp	(revision 4)
+++ /trunk/EraserDll/Pass.cpp	(revision 4)
@@ -0,0 +1,141 @@
+// Pass.cpp
+// Definitions for built-in wipe methods
+//
+// Eraser. Secure data removal. For Windows.
+// Copyright © 1997-2001  Sami Tolvanen (sami@tolvanen.com).
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#define PASS_CPP
+
+#include "stdafx.h"
+#include "EraserDll.h"
+
+///////////////////////////////////////////////////////////////////////////////
+// include here the header files for all built-in methods
+#include "Gutmann.h"
+#include "DoD.h"
+#include "RND.h"
+#include "Custom.h"
+#include "FirstLast2kb.h"
+#include "Schneier7pass.h"
+
+///////////////////////////////////////////////////////////////////////////////
+// pass arrays
+const PASS passGutmann[PASSES_GUTMANN] = {
+    passRandom,                        // 1
+    passRandom,
+    passRandom,
+    passRandom,
+    passOne(0x55),                     // 5
+    passOne(0xAA),
+    passThree(0x92, 0x49, 0x24),
+    passThree(0x49, 0x24, 0x92),
+    passThree(0x24, 0x92, 0x49),
+    passOne(0x00),                     // 10
+    passOne(0x11),
+    passOne(0x22),
+    passOne(0x33),
+    passOne(0x44),
+    passOne(0x55),                     // 15
+    passOne(0x66),
+    passOne(0x77),
+    passOne(0x88),
+    passOne(0x99),
+    passOne(0xAA),                     // 20
+    passOne(0xBB),
+    passOne(0xCC),
+    passOne(0xDD),
+    passOne(0xEE),
+    passOne(0xFF),                     // 25
+    passThree(0x92, 0x49, 0x24),
+    passThree(0x49, 0x24, 0x92),
+    passThree(0x24, 0x92, 0x49),
+    passThree(0x6D, 0xB6, 0xDB),
+    passThree(0xB6, 0xDB, 0x6D),       // 30
+    passThree(0xDB, 0x6D, 0xB6),
+    passRandom,
+    passRandom,
+    passRandom,
+    passRandom                         // 35
+};
+
+const PASS passDOD[PASSES_DOD] = {
+    passOne(0x55),                     // E (replaced with a random character)
+    passOne(0xAA),
+    passRandom,
+    passOne(0x00),                     // C (replaced with a random character)
+    passOne(0x55),                     // E (replaced with a random character)
+    passOne(0xAA),
+    passRandom
+};
+
+const PASS passDOD_E[PASSES_DOD_E] = {
+    passOne(0x00),                     // E
+    passOne(0xFF),
+    passRandom
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// the array of built-in methods (add #defines to Pass.h)
+const BMETHOD bmMethods[nBuiltinMethods] = {
+    bmEntry(GUTMANN_METHOD_ID,       // REQUIRED: ID
+            "Gutmann",               // REQUIRED: Description (max. 80 chars)
+            PASSES_GUTMANN,          // REQUIRED: Passes
+            wipeFileWithGutmann,     // REQUIRED: Wipe function
+            1,                       // OPTIONAL: Shuffle passes (depends on wipe function)
+            passGutmann),            // OPTIONAL: Pointer to pass array (depends on wipe function)
+
+    bmEntry(DOD_METHOD_ID,
+            "US DoD 5220.22-M (8-306. / E, C and E)",
+            PASSES_DOD,
+            wipeFileWithDoD,
+            0,
+            passDOD),
+
+    bmEntry(DOD_E_METHOD_ID,
+            "US DoD 5220.22-M (8-306. / E)",
+            PASSES_DOD_E,
+            wipeFileWithCustom,     // There's no need to write yet another wipe function...
+            0,
+            passDOD_E),
+
+    bmEntry(RANDOM_METHOD_ID,
+            "Pseudorandom Data",
+            PASSES_RND,
+            wipeFileWithPseudoRandom,
+            0,
+            0),
+
+	bmEntry(FL2KB_METHOD_ID,
+			"Only first and last 2KB",
+			PASSES_FL2KB,
+			wipeFileWithFirstLast2kb,
+			0,
+			0),
+
+	bmEntry(SCHNEIER_METHOD_ID,
+			"Schneier's 7 pass",
+			PASSES_SCHNEIER,
+			wipeFileWithSchneier7Pass,
+			0,
+			0)			
+
+};
+const BMETHOD* GetBMethods() 
+{
+	return &bmMethods[0];
+}
Index: /trunk/EraserDll/NTFS.cpp
===================================================================
--- /trunk/EraserDll/NTFS.cpp	(revision 4)
+++ /trunk/EraserDll/NTFS.cpp	(revision 4)
@@ -0,0 +1,647 @@
+// NTFS.cpp
+//
+// Eraser. Secure data removal. For Windows.
+// Copyright © 1997-2001  Sami Tolvanen (sami@tolvanen.com).
+//
+// SDelete - Secure Delete
+// Copyright (C) 1999 Mark Russinovich
+// Systems Internals - http://www.sysinternals.com
+//
+// This program implements a secure delete function for
+// Windows NT/2K. It even works on WinNT compressed, encrypted
+// and sparse files.
+//
+// This program is copyrighted. You may not use the source, or
+// derived version of the source, in a secure delete application.
+// You may use the source or techniques herein in applications
+// with a purpose other than secure delete.
+
+#include "stdafx.h"
+#include "resource.h"
+#include "EraserDll.h"
+#include "Common.h"
+#include "File.h"
+#include "NTFS.h"
+#include "winioctl.h"
+// Invalid longlong number
+
+#define LLINVALID       ((E_UINT64) -1)
+
+// Size of the buffer we read file mapping information into.
+// The buffer is big enough to hold the 16 bytes that
+// come back at the head of the buffer (the number of entries
+// and the starting virtual cluster), as well as 512 pairs
+// of [virtual cluster, logical cluster] pairs.
+
+#define FILEMAPSIZE     (16384 + 2)
+
+
+static bool
+initEntryPoints(NTFSContext& ntc)
+{
+    // load the NTDLL entry point we need
+    ntc.m_hNTDLL = AfxLoadLibrary(ERASER_MODULENAME_NTDLL);
+
+    if (ntc.m_hNTDLL != NULL) {
+        ntc.NtFsControlFile =
+            (NTFSCONTROLFILE) GetProcAddress(ntc.m_hNTDLL, ERASER_FUNCTIONNAME_NTFSCONTROLFILE);
+        ntc.NtQueryInformationFile =
+            (NTQUERYINFORMATIONFILE) GetProcAddress(ntc.m_hNTDLL, ERASER_FUNCTIONNAME_NTQUERYINFORMATIONFILE);
+        ntc.RtlNtStatusToDosError =
+            (RTLNTSTATUSTODOSERROR) GetProcAddress(ntc.m_hNTDLL, ERASER_FUNCTIONNAME_RTLNTSTATUSTODOSERROR);
+
+        if (ntc.NtFsControlFile == NULL || ntc.RtlNtStatusToDosError == NULL) {
+            AfxFreeLibrary(ntc.m_hNTDLL);
+            ntc.m_hNTDLL = NULL;
+        }
+    }
+
+    return (ntc.m_hNTDLL != NULL);
+}
+
+static CString
+formatNTError(NTFSContext& ntc, NTSTATUS dwStatus)
+{
+    CString strMessage;
+    LPTSTR szMessage;
+
+    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+                  NULL,
+                  ntc.RtlNtStatusToDosError(dwStatus),
+                  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+                  (LPTSTR)&szMessage, 0, NULL);
+
+    strMessage = szMessage;
+    LocalFree(szMessage);
+
+    return strMessage;
+}
+
+static bool
+wipeClusters(NTFSContext& ntc, CEraserContext *context, bool& bCompressed)
+{
+    if (context->m_piCurrent.m_uCluster == 0) {
+        return false;
+    }
+
+    NTSTATUS                  status = STATUS_INVALID_PARAMETER;
+    E_INT32                   i;
+    IO_STATUS_BLOCK           ioStatus;
+    E_UINT64                  startVcn;
+    PGET_RETRIEVAL_DESCRIPTOR fileMappings;
+    E_UINT64                  fileMap[FILEMAPSIZE];
+    HANDLE                    hFile;
+
+    // set the handle passed to the wipe function
+    hFile = context->m_hFile;
+    context->m_hFile = ntc.m_hVolume;
+
+    // assume file is in an MFT record.
+    bCompressed = false;
+
+    startVcn = 0;
+    fileMappings = (PGET_RETRIEVAL_DESCRIPTOR) fileMap;
+
+    status = ntc.NtFsControlFile(hFile, NULL, NULL, 0, &ioStatus,
+                              FSCTL_GET_RETRIEVAL_POINTERS,
+                              &startVcn, sizeof(startVcn),
+                              fileMappings,
+                              FILEMAPSIZE * sizeof(ULONGLONG));
+
+    while (status == STATUS_SUCCESS || status == STATUS_BUFFER_OVERFLOW ||
+           status == STATUS_PENDING) {
+        // if the operation is pending, wait for it to finish
+        if (status == STATUS_PENDING) {
+            WaitForSingleObject(hFile, INFINITE);
+
+            // get the status from the status block
+            if (ioStatus.Status != STATUS_SUCCESS &&
+                ioStatus.Status != STATUS_BUFFER_OVERFLOW) {
+                context->m_hFile = hFile;
+                return false;
+            }
+        }
+
+        // progress information
+        context->m_uProgressSize = 0;
+
+        startVcn = fileMappings->StartVcn;
+
+        for (i = 0; i < (E_UINT64) fileMappings->NumberOfPairs; i++) {
+            if (fileMappings->Pair[i].Lcn != LLINVALID) {
+                context->m_uProgressSize += (fileMappings->Pair[i].Vcn - startVcn) *
+                                            (E_UINT64)context->m_piCurrent.m_uCluster;
+            }
+
+            startVcn = fileMappings->Pair[i].Vcn;
+        }
+
+        eraserProgressStartEstimate(context, context->m_uProgressSize);
+
+        // loop through the buffer of number/cluster pairs, printing them out.
+        startVcn = fileMappings->StartVcn;
+
+        for (i = 0; i < (E_UINT64)fileMappings->NumberOfPairs; i++) {
+            // On NT 4.0, a compressed virtual run (0-filled) is
+            // identified with a cluster offset of -1
+
+            if (fileMappings->Pair[i].Lcn != LLINVALID) {
+                // its compressed and outside the zone
+                bCompressed = true;
+
+                // Overwrite the clusters if we were able to open the volume
+                // for write access.
+                context->m_uiFileStart.QuadPart = fileMappings->Pair[i].Lcn * context->m_piCurrent.m_uCluster;
+                context->m_uiFileSize.QuadPart = (fileMappings->Pair[i].Vcn - startVcn) *
+                                                 (E_UINT64)context->m_piCurrent.m_uCluster;
+
+                if (!context->m_lpmMethod->m_pwfFunction(context)) {
+                    context->m_hFile = hFile;
+                    return false;
+                }
+
+            }
+
+            startVcn = fileMappings->Pair[i].Vcn;
+        }
+
+        // if the buffer wasn't overflowed, then we're done
+        if (NT_SUCCESS(status)) {
+            break;
+        }
+
+        status = ntc.NtFsControlFile(hFile, NULL, NULL, 0, &ioStatus,
+                                  FSCTL_GET_RETRIEVAL_POINTERS,
+                                  &startVcn, sizeof(startVcn),
+                                  fileMappings,
+                                  FILEMAPSIZE * sizeof(E_UINT64));
+    }
+
+    if (status != STATUS_SUCCESS && status != STATUS_INVALID_PARAMETER) {
+        context->m_saError.Add(formatNTError(ntc, status));
+    }
+
+    // restore the file handle
+    context->m_hFile = hFile;
+
+    // if we made through with no errors we've overwritten all the file's clusters.
+    return NT_SUCCESS(status);
+}
+
+static bool
+initAndOpenVolume(NTFSContext& ntc, TCHAR cDrive)
+{
+    TCHAR szVolumeName[] = "\\\\.\\ :";
+
+    if (initEntryPoints(ntc)) {
+        // open the volume for direct access
+        szVolumeName[4] = cDrive;
+        ntc.m_hVolume = CreateFile(szVolumeName, GENERIC_READ | GENERIC_WRITE,
+                                   FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
+                                   OPEN_EXISTING, FILE_FLAG_WRITE_THROUGH, 0);
+
+        return (ntc.m_hVolume != INVALID_HANDLE_VALUE);
+    }
+    return false;
+}
+
+// exported functions
+//
+
+E_UINT32
+wipeCompressedFile(CEraserContext *context)
+{
+    if (!isFileSystemNTFS(context->m_piCurrent)) {
+        return WCF_NOTCOMPRESSED;
+    }
+
+    NTFSContext ntc;
+    E_UINT32 uResult = WCF_FAILURE;
+    bool bCompressed = false;
+
+    if (initAndOpenVolume(ntc, context->m_strData[0])) {
+        // open the file exclusively
+        context->m_hFile = CreateFile((LPCTSTR)context->m_strData, GENERIC_READ,
+                                      (context->m_uTestMode) ?
+                                        FILE_SHARE_READ | FILE_SHARE_WRITE : 0,
+                                      NULL, OPEN_EXISTING, 0, NULL);
+
+        if (context->m_hFile != INVALID_HANDLE_VALUE) {
+            try {
+                // scan the location of the file
+                if (wipeClusters(ntc, context, bCompressed)) {
+                    // done with the file handle
+                    CloseHandle(context->m_hFile);
+                    context->m_hFile = INVALID_HANDLE_VALUE;
+
+                    if (!bCompressed) {
+                        // if the file wasn't really compressed, erase normally
+                        uResult = WCF_NOTCOMPRESSED;
+                    } else {
+                        if (eraserOK(eraserRemoveFile((LPVOID)(LPCTSTR)context->m_strData,
+                                (E_UINT16)context->m_strData.GetLength()))) {
+                            uResult = WCF_SUCCESS;
+                        }
+                    }
+                } else {
+                    // close the handle
+                    CloseHandle(context->m_hFile);
+                    context->m_hFile = INVALID_HANDLE_VALUE;
+                }
+            } catch (CException *e) {
+                handleException(e, context);
+                uResult = WCF_FAILURE;
+
+                if (context->m_hFile != INVALID_HANDLE_VALUE) {
+                    CloseHandle(context->m_hFile);
+                    context->m_hFile = INVALID_HANDLE_VALUE;
+                }
+            }
+        }
+    } else {
+        // the user does not have privileges for low-level access
+        uResult = WCF_NOACCESS;
+    }
+
+    return uResult;
+}
+
+
+#define mftFastWriteTest(x) \
+    WriteFile((x)->m_hFile, uTestBuffer, (x)->m_uiFileSize.LowPart, &uTemp, NULL)
+
+bool
+wipeMFTRecords(CEraserContext *context)
+{
+    // On NTFS file system small files can be resident on the MFT record so we
+    // will need to overwrite empty records by creating as many of the largest
+    // sized files as possible (if there is space in the MFT, we'll be able to
+    // create non-zero sized files, where the data is resident in the MFT record)
+
+    if (!isFileSystemNTFS(context->m_piCurrent)) {
+        return false;
+    }
+
+    E_UINT64 uFreeSpace = 0;
+    eraserGetFreeDiskSpace((LPVOID)context->m_piCurrent.m_szDrive,
+                           (E_UINT16)lstrlen(context->m_piCurrent.m_szDrive),
+                           &uFreeSpace);
+
+    if (uFreeSpace == 0) {
+        const E_UINT16 maxMFTRecordSize = 4096;
+
+        TCHAR        szFileName[uShortFileNameLength + 1];
+        E_UINT16     uCounter = 1;
+        E_UINT32     uTestBuffer[maxMFTRecordSize];
+        E_UINT32     uTemp;
+        E_UINT64     ulPrevSize = maxMFTRecordSize;
+        CString      strTemp;
+        CStringArray saList;
+        bool         bCreatedFile;
+
+        // fill test buffer with random data
+        isaacFill((E_PUINT8)uTestBuffer, maxMFTRecordSize);
+
+        // do something with the progress bar to entertain the user
+        eraserDispMFT(context);
+        eraserBeginNotify(context);
+
+        context->m_uClusterSpace = 0;
+
+        do {
+            createRandomShortFileName(szFileName, uCounter++);
+            strTemp.Format("Eraser%s%s", context->m_piCurrent.m_szDrive, szFileName);
+
+            context->m_hFile = CreateFile((LPCTSTR)strTemp,
+                                         GENERIC_WRITE,
+                                         (context->m_uTestMode) ?
+                                            FILE_SHARE_READ | FILE_SHARE_WRITE : 0,
+                                         NULL,
+                                         CREATE_NEW,
+                                         FILE_ATTRIBUTE_HIDDEN | FILE_FLAG_WRITE_THROUGH,
+                                         NULL);
+
+            if (context->m_hFile == INVALID_HANDLE_VALUE) {
+                break;
+            }
+
+            saList.Add(strTemp);
+
+            try {
+                context->m_uiFileStart.QuadPart = 0;
+                context->m_uiFileSize.QuadPart = ulPrevSize;
+                bCreatedFile = false;
+
+                while (context->m_uiFileSize.QuadPart) {
+                    if (eraserInternalTerminated(context)) {
+                        bCreatedFile = false;
+                        break;
+                    }
+
+                    // trying simple write first is much faster than calling the wipe function
+                    if (!mftFastWriteTest(context) || !context->m_lpmMethod->m_pwfFunction(context)) {
+                        eraserProgressSetMessage(context, ERASER_MESSAGE_MFT);
+                        context->m_uiFileSize.QuadPart--;
+                    } else {
+                        strTemp.Format(ERASER_MESSAGE_MFT_WAIT, uCounter);
+                        eraserProgressSetMessage(context, strTemp);
+                        eraserUpdateNotify(context);
+
+                        ulPrevSize = context->m_uiFileSize.QuadPart;
+                        bCreatedFile = true;
+                        break;
+                    }
+
+                    eraserSafeAssign(context, context->m_uProgressPercent,
+                        (E_UINT8)(((maxMFTRecordSize - context->m_uiFileSize.QuadPart) * 100) / maxMFTRecordSize));
+                    setTotalProgress(context);
+                    eraserUpdateNotify(context);
+                }
+            } catch (CException *e) {
+                handleException(e, context);
+                bCreatedFile = false;
+            }
+
+            resetDate(context->m_hFile);
+            CloseHandle(context->m_hFile);
+
+        } while (bCreatedFile);
+
+        eraserSafeAssign(context, context->m_uProgressPercent, 100);
+        setTotalProgress(context);
+
+        eraserProgressSetMessage(context, ERASER_MESSAGE_REMOVING);
+        eraserUpdateNotify(context);
+
+        E_INT32 iSize = saList.GetSize();
+        for (E_INT32 i = 0; i < iSize; i++) {
+            eraserSafeAssign(context, context->m_uProgressPercent, (E_UINT8)((i * 100) / iSize));
+            eraserUpdateNotify(context);
+
+            // file names are already random, no need to use slower eraserRemoveFile
+            DeleteFile((LPCTSTR)saList[i]);
+        }
+
+        // add entropy to the pool, number of files created
+        randomAddEntropy((E_PUINT8)&iSize, sizeof(E_INT32));
+
+        eraserSafeAssign(context, context->m_uProgressPercent, 100);
+        eraserUpdateNotify(context);
+
+        // clean up
+        ZeroMemory(uTestBuffer, maxMFTRecordSize);
+
+        return true;
+    }
+
+    return false;
+}
+
+bool
+wipeNTFSFileEntries(CEraserContext *context)
+{
+    if (!isFileSystemNTFS(context->m_piCurrent)) {
+        return false;
+    }
+
+    NTFSContext ntc;
+    bool bResult = false;
+
+    if (initAndOpenVolume(ntc, context->m_strData[0])) {
+        IO_STATUS_BLOCK ioStatus;
+        NTSTATUS status;
+        NTFS_VOLUME_DATA_BUFFER nvd;
+
+        // find out MFT size
+        status = ntc.NtFsControlFile(ntc.m_hVolume, NULL, NULL, 0, &ioStatus,
+                                     FSCTL_GET_VOLUME_INFORMATION,
+                                     NULL, 0, &nvd,
+                                     sizeof(NTFS_VOLUME_DATA_BUFFER));
+
+        if (status == STATUS_SUCCESS) {
+            const E_UINT32  uMaxFilesPerFolder = 3000;
+            const E_UINT32  uMFTPollInterval = 20;
+            const E_UINT32  uFileNameLength = _MAX_FNAME - 14 /*strFolder.GetLength() + 1*/ - 8 - 1;
+
+            HANDLE          hFile, hFind;
+            WIN32_FIND_DATA wfdData;
+            E_UINT32        uSpeed, uTickCount;
+            E_UINT32        i, j;
+            E_UINT32        uFiles = 0, uFolders = 0;
+            E_UINT32        uEstimate;
+            LARGE_INTEGER   uOriginalMFTSize = nvd.MftValidDataLength;
+            CString         strPath, strFolder;
+            CStringArray    saFolders;
+            TCHAR           szPrefix[uFileNameLength + 1];
+
+            try {
+                // prefix each name with a couple of zeros
+                for (i = 0; i < uFileNameLength; i++) {
+                    szPrefix[i] = '0';
+                }
+                szPrefix[uFileNameLength] = 0;
+
+                // approximate the number of files we need to create (at least 1)
+				uEstimate = max(1, (E_UINT32)(nvd.MftValidDataLength.QuadPart / nvd.BytesPerFileRecordSegment));
+
+                if (uEstimate > context->m_uProgressFiles) {
+                    uEstimate -= context->m_uProgressFiles;
+                }
+
+                // this may take a while, so we'll try to estimate the time
+                context->m_uProgressFlags |= eraserDispTime;
+                context->m_uProgressStartTime = GetTickCount();
+
+                eraserBeginNotify(context);
+
+                do {
+                    if (uFiles % uMaxFilesPerFolder == 0) {
+                        strFolder.Format("%c:\\%s%04X", context->m_strData[0],
+                                    ERASER_TEMP_DIRECTORY_NTFS_ENTRIES, uFolders++);
+
+                        // remove possibly existing folder
+                        eraserRemoveFolder((LPVOID)(LPCTSTR)strFolder, (E_UINT16)strFolder.GetLength(),
+                                           ERASER_REMOVE_RECURSIVELY);
+
+                        // create new directory
+                        if (CreateDirectory((LPCTSTR)strFolder, NULL)) {
+                            saFolders.Add(strFolder + "\\");
+                        } else {
+                            eraserAddError(context, IDS_ERROR_TEMPFILE);
+                            break;
+                        }
+                    }
+
+                    strPath.Format("%s\\%s%08X", strFolder, szPrefix, uFiles);
+
+                    hFile = CreateFile((LPCTSTR)strPath, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, 0);
+
+                    if (hFile != INVALID_HANDLE_VALUE) {
+                        uFiles++;
+                        CloseHandle(hFile);
+                    } else {
+                        eraserAddError(context, IDS_ERROR_TEMPFILE);
+                        break;
+                    }
+
+                    if (uFiles % uMFTPollInterval == 0 || eraserInternalTerminated(context)) {
+                        status = ntc.NtFsControlFile(ntc.m_hVolume, NULL, NULL, 0, &ioStatus,
+                                                     FSCTL_GET_VOLUME_INFORMATION,
+                                                     NULL, 0, &nvd,
+                                                     sizeof(NTFS_VOLUME_DATA_BUFFER));
+
+                        if (eraserInternalTerminated(context)) {
+                            break;
+                        } else {
+                            uTickCount = GetTickCount();
+                            if (uTickCount > context->m_uProgressStartTime) {
+                                uSpeed = (uFiles * 1000) / (uTickCount - context->m_uProgressStartTime);
+
+                                if (uSpeed > 0) {
+                                    context->m_uProgressTimeLeft = ((uEstimate - uFiles) / uSpeed);
+                                } else {
+                                    context->m_uProgressTimeLeft = 0;
+                                }
+                            }
+
+                            eraserSafeAssign(context, context->m_uProgressPercent,
+                                (E_UINT8)min(100, (uFiles * 100) / uEstimate));
+                            setTotalProgress(context);
+                            eraserUpdateNotify(context);
+                        }
+                    }
+				} while (status == STATUS_SUCCESS && nvd.MftValidDataLength.QuadPart <= uOriginalMFTSize.QuadPart);
+					
+
+                // if we managed to increase MFT size, slack space was filled
+				if (nvd.MftValidDataLength.QuadPart > uOriginalMFTSize.QuadPart) {
+                    bResult = true;
+                    eraserSafeAssign(context, context->m_uProgressPercent, 100);
+                    setTotalProgress(context);
+
+                    // add entropy to the pool, number of files created
+                    randomAddEntropy((E_PUINT8)&uFiles, sizeof(E_UINT32));
+                }
+
+                if (!eraserInternalTerminated(context)) {
+                    // show progress bar while removing files - may take a while
+                    eraserProgressSetMessage(context, ERASER_MESSAGE_REMOVING);
+                    eraserBeginNotify(context);
+                }
+
+                // remove temporary files
+                for (i = 0, j = 0; i < uFolders; i++) {
+                    strFolder = saFolders[i];
+                    hFind = FindFirstFile((LPCTSTR)(strFolder + "*"), &wfdData);
+
+                    if (hFind != INVALID_HANDLE_VALUE) {
+                        do {
+                            if (!bitSet(wfdData.dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY)) {
+                                // eraserRemoveFile is way too slow
+                                DeleteFile((LPCTSTR)(strFolder + wfdData.cFileName));
+
+                                if (!eraserInternalTerminated(context)) {
+                                    eraserSafeAssign(context, context->m_uProgressPercent, (E_UINT8)((++j * 100) / uFiles));
+                                    eraserUpdateNotify(context);
+                                }
+                            }
+                        }
+                        while (FindNextFile(hFind, &wfdData));
+
+                        VERIFY(FindClose(hFind));
+                    }
+
+                    // remove the folder
+                    if (eraserError(eraserRemoveFolder((LPVOID)(LPCTSTR)strFolder,
+                            (E_UINT16)strFolder.GetLength(), ERASER_REMOVE_RECURSIVELY))) {
+                        context->m_saFailed.Add(strFolder);
+                    }
+                }
+
+                if (!eraserInternalTerminated(context)) {
+                    // and we're done
+                    eraserSafeAssign(context, context->m_uProgressPercent, 100);
+                    eraserUpdateNotify(context);
+                }
+            } catch (CException *e) {
+                handleException(e, context);
+                bResult = false;
+            }
+        }
+    }
+
+    if (!bResult) {
+        eraserAddError1(context, IDS_ERROR_DIRENTRIES, (LPCTSTR)context->m_strData);
+    }
+
+    return bResult;
+}
+
+bool
+findAlternateDataStreams(CEraserContext *context, LPCTSTR szFile, DataStreamArray& streams)
+{
+    if (!isFileSystemNTFS(context->m_piCurrent)) {
+        return false;
+    }
+
+    NTFSContext ntc;
+    if (initEntryPoints(ntc)) {
+        bool bResult = false;
+        HANDLE hFile;
+        PFILE_STREAM_INFORMATION psi = 0;
+        NTSTATUS status = STATUS_INVALID_PARAMETER;
+        WCHAR wszStreamName[MAX_PATH];
+        IO_STATUS_BLOCK ioStatus;
+        DataStream ads;
+
+        hFile = CreateFile(szFile,
+                           GENERIC_READ,
+                           FILE_SHARE_READ | FILE_SHARE_WRITE,
+                           NULL,
+                           OPEN_EXISTING,
+                           0, 0);
+
+        if (hFile != INVALID_HANDLE_VALUE) {
+            // use write buffer, should be large enough
+            status = ntc.NtQueryInformationFile(hFile, &ioStatus,
+                                                (PFILE_STREAM_INFORMATION)context->m_puBuffer,
+                                                ERASER_DISK_BUFFER_SIZE,
+                                                FileStreamInformation);
+
+            if (NT_SUCCESS(status)) {
+                try {
+                    psi = (PFILE_STREAM_INFORMATION)context->m_puBuffer;
+
+                    do {
+                        memcpy(wszStreamName, psi->Name, psi->NameLength);
+                        wszStreamName[psi->NameLength / sizeof(WCHAR)] = 0;
+
+                        if (wcsicmp(wszStreamName, L"::$DATA")) {
+                            // name of the alternate data stream
+                            unicodeToCString(wszStreamName, ads.m_strName);
+                            ads.m_strName = szFile + ads.m_strName;
+
+                            ads.m_uSize = psi->Size.QuadPart;
+                            streams.Add(ads);
+                        }
+
+                        if (psi->NextEntry) {
+                            psi = (PFILE_STREAM_INFORMATION)((E_PUINT8)psi + psi->NextEntry);
+                        } else {
+                            psi = 0;
+                        }
+                    } while (psi);
+
+                    bResult = true;
+                } catch (...) {
+                    ASSERT(0);
+                    bResult = false;
+                }
+            }
+
+            CloseHandle(hFile);
+            return bResult;
+        }
+    }
+    return false;
+}
Index: /trunk/EraserDll/FileLockResolver.cpp
===================================================================
--- /trunk/EraserDll/FileLockResolver.cpp	(revision 4)
+++ /trunk/EraserDll/FileLockResolver.cpp	(revision 4)
@@ -0,0 +1,214 @@
+// FileLockResolver.cpp
+//
+// Eraser. Secure data removal. For Windows.
+// Copyright © 1997-2001  Sami Tolvanen (sami@tolvanen.com).
+// Copyright © 2001-2006  Garrett Trant (support@heidi.ie).
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+#include "stdafx.h"
+#include "FileLockResolver.h"
+#include <fstream>
+#include <string>
+#include <iterator>
+#include <atlbase.h>
+
+#define LOCKED_FILE_LIST_NAME _T("lock")
+#define RUNONCE  "Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce"
+#define LAUNCHER "Eraserl.exe"
+
+CFileLockResolver::CFileLockResolver(BOOL askUser)
+: m_bAskUser(askUser), m_hHandle(ERASER_INVALID_CONTEXT)
+{
+
+}
+CFileLockResolver::CFileLockResolver(ERASER_HANDLE h, BOOL askUser)
+: m_bAskUser(askUser)
+{
+	SetHandle(h);
+}
+
+void 
+CFileLockResolver::SetHandle(ERASER_HANDLE h)
+{
+	m_hHandle = h;
+	eraserSetErrorHandler(h, ErrorHandler, this);
+}
+
+CFileLockResolver::~CFileLockResolver(void)
+{
+	Close();
+}
+struct PathHelper
+{
+	CString& m_strLockFile;
+	PathHelper(CString& lockFile, bool path_only = false)
+		:m_strLockFile(lockFile)
+	{
+	
+		char fullname[MAX_PATH];
+		char filename[MAX_PATH];
+		char extension[MAX_PATH];
+		char pathname[MAX_PATH];
+		char drive[10];
+
+
+
+		GetModuleFileName(AfxGetInstanceHandle(),fullname,sizeof (fullname));
+		_splitpath(fullname,drive, pathname, filename, extension); 
+		
+		m_strLockFile = drive;
+		m_strLockFile += pathname;
+		if (path_only )
+			return;
+		m_strLockFile.Format("%s%s%d.%s", drive, pathname, time(0), LOCKED_FILE_LIST_NAME);
+
+
+	}
+};
+struct FileData
+{
+	std::string name;
+	int method;
+	unsigned int passes;
+
+	FileData()
+	{
+	}
+	FileData(const std::string& fname, int m, unsigned int pass)
+		:name(fname), method(m), passes(pass)
+	{
+	}
+
+	void read(std::istream& is)
+	{
+	
+		is >> std::noskipws;
+		std::getline(is, name);
+		
+	}
+
+	void write(std::ostream& os) const
+	{
+		
+		os << std::noskipws;
+		os << name << std::endl;
+		
+	}
+};
+std::ostream& operator << (std::ostream& os, const FileData& data)
+{
+	data.write(os);
+	return os;
+}
+std::istream& operator >> (std::istream& is, FileData& data)
+{
+	data.read(is);
+	return is;
+}
+void 
+CFileLockResolver::HandleError(LPCTSTR szFileName, DWORD dwErrorCode, int em, unsigned int passes)
+{
+	if (ERROR_LOCK_VIOLATION == dwErrorCode 
+		|| ERROR_DRIVE_LOCKED == dwErrorCode
+		|| ERROR_LOCKED == dwErrorCode
+		|| ERROR_SHARING_VIOLATION == dwErrorCode)
+	{
+		bool needResolve = true;
+		if (TRUE == m_bAskUser )
+		{
+			 needResolve = (IDYES == AfxGetMainWnd()->MessageBox("File locked by another process." 
+			"Do you want to Erase after restart?", "Error", MB_YESNO | MB_ICONQUESTION));			
+		}
+
+		if (needResolve)
+		{
+			static PathHelper	path(m_strLockFileList);
+			std::ofstream os(m_strLockFileList, std::ios_base::out | std::ios_base::app);		
+			os << FileData(szFileName, em, passes);
+
+		}
+		
+
+		/*if (TRUE == m_bAskUser 
+		&& IDYES == AfxGetMainWnd()->MessageBox("File locked by another process." 
+		"Do you want to Erase after restart?", "Error", MB_YESNO | MB_ICONQUESTION))
+		{
+		static PathHelper	path(m_strLockFileList);
+		std::ofstream os(m_strLockFileList, std::ios_base::out | std::ios_base::app);		
+		os << FileData(szFileName, em, passes);
+		}*/
+		
+	}
+	
+}
+void 
+CFileLockResolver::Resolve(LPCTSTR szFileName)
+{
+	
+}
+
+void 
+CFileLockResolver::Resolve(LPCTSTR szFileName, CStringArray& ar)
+{
+	std::ifstream is(szFileName);
+	if (is.fail())
+		throw std::runtime_error("Unable to resolve locked files. Can't open file list");
+
+	while (!is.eof()) 
+	{
+		FileData data;
+		is >> data;
+		if (!data.name.empty())
+			ar.Add(data.name.c_str());
+	}
+	is.close();
+	DeleteFile(szFileName);
+}
+DWORD 
+CFileLockResolver::ErrorHandler(LPCTSTR szFileName, DWORD dwErrorCode, void* ctx, void* param)
+{
+	CFileLockResolver* self(static_cast<CFileLockResolver*>(param));
+	CEraserContext* ectx(static_cast<CEraserContext* >(ctx));
+	self->HandleError(szFileName, dwErrorCode, ectx->m_lpmMethod->m_nMethodID, ectx->m_lpmMethod->m_nPasses);
+	return 0UL;
+}
+
+void
+CFileLockResolver::Close()
+{
+	eraserSetErrorHandler(m_hHandle, NULL, NULL);
+
+	if (m_strLockFileList.IsEmpty())
+		return;
+
+	CString strPath;
+	PathHelper(strPath, true);
+	strPath = CString("\"") + strPath ;
+	strPath += LAUNCHER;
+	strPath += "\" -rl \"";
+	strPath += m_strLockFileList + "\"";
+
+	extern bool no_registry;
+	if (!no_registry)
+	{
+		CRegKey key;
+		if (ERROR_SUCCESS == key.Open(HKEY_LOCAL_MACHINE, RUNONCE))
+		{
+			key.SetStringValue(LAUNCHER, strPath);
+			m_strLockFileList = "";
+		}
+	}
+}
Index: /trunk/EraserDll/FAT.cpp
===================================================================
--- /trunk/EraserDll/FAT.cpp	(revision 4)
+++ /trunk/EraserDll/FAT.cpp	(revision 4)
@@ -0,0 +1,1395 @@
+// FAT.cpp
+//
+// Eraser. Secure data removal. For Windows.
+// Copyright © 1997-2001  Sami Tolvanen (sami@tolvanen.com).
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#include "stdafx.h"
+#include <winioctl.h>
+#include "Resource.h"
+#include "EraserDll.h"
+#include "Common.h"
+#include "FreeSpace.h"
+#include "FAT.h"
+
+// path to VWIN32.vxd
+//
+const LPCTSTR szVWIN32 = "\\\\.\\vwin32";
+
+// helpful definitions
+//
+#define isClusterNotEnd(pwInfo, uIndex) \
+    ((uIndex) <= (pwInfo)->FS.uLowValue)
+#define isClusterError(pwInfo, uIndex) \
+    (((uIndex) > (pwInfo)->FS.uLowValue) && ((uIndex) <= (pwInfo)->FS.uErrorValue))
+#define clusterToSector(pwInfo, uCluster) \
+    ((((uCluster) - 0x2) * (pwInfo)->m_uSectorsPerCluster) + (pwInfo)->m_uStartSector)
+#define isEntryLocked(pwInfo) \
+    (((pwInfo)->m_uVolumeLocked > 0) || ((pwInfo)->m_hDirectory != INVALID_HANDLE_VALUE))
+
+#define MAX_SECTOR_BUFFER   2048
+
+#define FAT12_MAX_CLUSTERS  0xFF0
+#define FAT12_MAX_ERROR     0xFF7
+#define FAT12_MAX_VALUE     0xFFF
+
+#define FAT16_MAX_CLUSTERS  0xFFF0
+#define FAT16_MAX_ERROR     0xFFF7
+#define FAT16_MAX_VALUE     0xFFFF
+
+#define FAT32_MAX_CLUSTERS  0x0FFFFFF0
+#define FAT32_MAX_ERROR     0x0FFFFFF7
+#define FAT32_MAX_VALUE     0x0FFFFFFF
+
+
+// NT specific functions
+//
+static DISKERROR
+readSectors_NT(wfeInfo *pwInfo, E_UINT32 uStartSector, E_UINT16 uSectors, E_PUINT8 pBuffer)
+{
+    ULARGE_INTEGER uiStart;
+    E_UINT32 uSize = uSectors * pwInfo->m_uSectorSize;
+    E_UINT32 uResult = 0;
+
+    uiStart.QuadPart = UInt32x32To64(uStartSector, (E_UINT32)pwInfo->m_uSectorSize);
+
+    uResult = SetFilePointer(pwInfo->m_hVolume, uiStart.LowPart, (E_PINT32)&uiStart.HighPart, FILE_BEGIN);
+
+    if (uResult == (E_UINT32)-1 && GetLastError() != NO_ERROR) {
+        return DISK_FAILURE;
+    }
+
+    if (ReadFile(pwInfo->m_hVolume, pBuffer, uSize, &uResult, NULL) && (uSize == uResult)) {
+        return DISK_SUCCESS;
+    } else {
+        return DISK_FAILURE;
+    }
+}
+
+static DISKERROR
+writeSectors_NT(wfeInfo *pwInfo, E_UINT32 uStartSector, E_UINT16 uSectors, E_PUINT8 pBuffer)
+{
+    ULARGE_INTEGER uiStart;
+    E_UINT32 uSize = uSectors * pwInfo->m_uSectorSize;
+    E_UINT32 uResult = 0;
+
+    uiStart.QuadPart = UInt32x32To64(uStartSector, (E_UINT32)pwInfo->m_uSectorSize);
+
+    uResult = SetFilePointer(pwInfo->m_hVolume, uiStart.LowPart, (E_PINT32)&uiStart.HighPart, FILE_BEGIN);
+
+    if (uResult == (E_UINT32)-1 && GetLastError() != NO_ERROR) {
+        return DISK_FAILURE;
+    }
+
+    if (WriteFile(pwInfo->m_hVolume, pBuffer, uSize, &uResult, NULL) && (uSize == uResult)) {
+        return DISK_SUCCESS;
+    } else {
+        return DISK_FAILURE;
+    }
+}
+
+static DISKERROR
+lockVolume_NT(wfeInfo *pwInfo, E_INT32 /*lockLevel*/, E_INT32 /*permissions*/)
+{
+    if (pwInfo->m_uVolumeLocked > 0) {
+        pwInfo->m_uVolumeLocked++;
+        return DISK_SUCCESS;
+    }
+
+    E_UINT32 uResult = 0;
+
+    if (DeviceIoControl(pwInfo->m_hVolume, FSCTL_LOCK_VOLUME,
+            NULL, 0, NULL, 0, &uResult, NULL)) {
+        pwInfo->m_uVolumeLocked = 1;
+    }
+
+    // return DISK_SUCCESS even if we couldn't lock
+    // the volume - we'll just attempt to lock the
+    // directory instead
+
+    return DISK_SUCCESS;
+}
+
+static DISKERROR
+unlockVolume_NT(wfeInfo *pwInfo)
+{
+    if (pwInfo->m_uVolumeLocked > 1) {
+        pwInfo->m_uVolumeLocked--;
+        return DISK_SUCCESS;
+    }
+
+    if (pwInfo->m_uVolumeLocked == 1) {
+        E_UINT32 uResult = 0;
+
+        if (DeviceIoControl(pwInfo->m_hVolume, FSCTL_UNLOCK_VOLUME,
+                NULL, 0, NULL, 0, &uResult, NULL)) {
+            pwInfo->m_uVolumeLocked = 0;
+            return DISK_SUCCESS;
+        }
+    }
+
+    return DISK_FAILURE;
+}
+
+static DISKERROR
+lockState_NT(wfeInfo*)
+{
+    // always return DISK_NOP for compatibility
+    return DISK_NOP;
+}
+
+static DISKERROR
+unlockDirectory_NT(wfeInfo *pwInfo)
+{
+    if (pwInfo->m_hDirectory != INVALID_HANDLE_VALUE) {
+        CloseHandle(pwInfo->m_hDirectory);
+        pwInfo->m_hDirectory = INVALID_HANDLE_VALUE;
+        return DISK_SUCCESS;
+    } else {
+        return DISK_FAILURE;
+    }
+}
+
+static DISKERROR
+lockDirectory_NT(wfeInfo *pwInfo, LPCTSTR szDirectory)
+{
+    if (pwInfo->m_hDirectory != INVALID_HANDLE_VALUE) {
+        unlockDirectory_NT(pwInfo);
+    }
+
+    // open without sharing allowed
+    pwInfo->m_hDirectory = CreateFile(szDirectory, GENERIC_READ | GENERIC_WRITE,
+                            0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+
+    if (pwInfo->m_hDirectory == INVALID_HANDLE_VALUE) {
+        return DISK_FAILURE;
+    } else {
+        return DISK_SUCCESS;
+    }
+}
+
+
+// FAT32 specific functions
+//
+static DISKERROR
+readSectors_FAT32(wfeInfo *pwInfo, E_UINT32 uStartSector, E_UINT16 uSectors, E_PUINT8 pBuffer)
+{
+    // mov  si, 0h             ; SI = 0 for read
+    //
+    // mov  cx, -1             ; cx must be -1
+    // mov  dx, seg Buffer
+    // mov  ds, dx
+    // mov  bx, offset Buffer  ; Pointers to a DISKIO structure
+    // mov  dl, DriveNum       ; The 1-based drive number
+    //                         ; (0 = default; 1 = A, 2 = B, and so on).
+    // mov  ax, 7305h          ; Ext_ABSDiskReadWrite
+    // int 21h
+    //
+    // jc  error_handler       ; carry set means error
+
+    DIOC_REGISTERS  reg;
+    DISKIO          di;
+    BOOL            bResult;
+    E_UINT32        cb;
+
+    reg.reg_EAX      = 0x7305;
+    reg.reg_EBX      = (E_UINT32)&di;
+    reg.reg_ECX      = 0xFFFF;
+    reg.reg_EDX      = pwInfo->m_iVolume;
+    reg.reg_ESI      = 0;
+    reg.reg_Flags    = 1;
+
+    // control block
+    di.diStartSector = uStartSector;
+    di.diSectors     = uSectors;
+    di.diBuffer      = (E_UINT32)pBuffer;
+
+    bResult = DeviceIoControl(pwInfo->m_hVolume, VWIN32_DIOC_DOS_DRIVEINFO,
+                              &reg, sizeof(reg), &reg,
+                              sizeof(reg), &cb, 0);
+
+    if (!bResult || bitSet(reg.reg_Flags, CARRY_FLAG)) {
+        return DISK_FAILURE;
+    }
+
+    return DISK_SUCCESS;
+}
+
+static DISKERROR
+writeSectors_FAT32(wfeInfo *pwInfo, E_UINT32 uStartSector, E_UINT16 uSectors, E_PUINT8 pBuffer)
+{
+    // mov  si, 6001h          ; write normal file data.
+    //
+    // mov  cx, -1             ; cx must be -1
+    // mov  dx, seg Buffer
+    // mov  ds, dx
+    // mov  bx, offset Buffer  ; Pointers to a DISKIO structure
+    // mov  dl, DriveNum       ; The 1-based drive number
+    //                         ; (0 = default; 1 = A, 2 = B, and so on).
+    // mov  ax, 7305h          ; Ext_ABSDiskReadWrite
+    // int 21h
+    //
+    // jc  error_handler       ; carry set means error
+
+    BOOL            bResult;
+    E_UINT32        cb;
+    DIOC_REGISTERS  reg;
+    DISKIO          di;
+
+    reg.reg_EAX         = 0x7305;
+    reg.reg_EBX         = (E_UINT32)&di;
+    reg.reg_ECX         = 0xFFFF;
+    reg.reg_EDX         = pwInfo->m_iVolume;
+    reg.reg_ESI         = 0x6001;
+    reg.reg_Flags       = 1;
+
+    // control block
+    di.diStartSector    = uStartSector;
+    di.diSectors        = uSectors;
+    di.diBuffer         = (E_UINT32)pBuffer;
+
+    bResult = DeviceIoControl(pwInfo->m_hVolume, VWIN32_DIOC_DOS_DRIVEINFO,
+                              &reg, sizeof(reg), &reg,
+                              sizeof(reg), &cb, 0);
+
+    if (!bResult || bitSet(reg.reg_Flags, CARRY_FLAG)) {
+        return DISK_FAILURE;
+    }
+
+    return DISK_SUCCESS;
+}
+
+static DISKERROR
+lockState_FAT32(wfeInfo *pwInfo)
+{
+    // mov ax, 440Dh        ; generic IOCTL
+    // mov bl, DriveNum     ; Drive to poll. 1-based.
+    // mov ch, DeviceCat    ; 48h for FAT32 drive
+    // mov cl, 6Ch          ; Get Lock Flag State
+    // int 21h
+    //
+    // jc error_handler
+    // mov [AccessFlag], ax  ; state of access flag
+
+    DIOC_REGISTERS  reg;
+    BOOL            bResult;
+    E_UINT32        cb;
+
+    reg.reg_EAX     = 0x440D;
+    reg.reg_ECX     = 0x486c;
+    reg.reg_EBX     = pwInfo->m_iVolume;
+    reg.reg_Flags   = 1;
+
+    bResult = DeviceIoControl(pwInfo->m_hVolume, VWIN32_DIOC_DOS_IOCTL,
+                              &reg, sizeof(reg), &reg,
+                              sizeof(reg), &cb, 0);
+
+    if (!bResult || bitSet(reg.reg_Flags, CARRY_FLAG)) {
+        return DISK_FAILURE;
+    }
+
+    return ((reg.reg_EAX == 0) ? DISK_NOP : DISK_WRITE);
+}
+
+static DISKERROR
+lockVolume_FAT32(wfeInfo *pwInfo, E_INT32 iLockLevel, E_INT32 iPermissions)
+{
+    // mov ax, 440Dh        ; generic IOCTL
+    // mov bh, LockLevel    ; Level of the lock. 0, 1, 2 or 3
+    // mov bl, DriveNum     ; Drive to lock. 0 for default, 1 for A,...
+    // mov ch, DeviceCat    ; 48h for FAT32 drive
+    // mov cl, 4Ah          ; Lock Logical Volume
+    // mov dx, Permissions  ; Bit  Meaning
+    //                        0    0 = Write operations are failed
+    //                        0    1 = Write operations are allowed
+    //                        1    0 = New file mapping are allowed
+    //                        1    1 = New file mapping are failed
+    //                        2    1 = The volume is locked for formatting
+    //                                 (specified when a level 0 lock is
+    //                                  obtained for the second time).
+    // int 21h
+    //
+    // jc error_handler
+
+    DIOC_REGISTERS  reg;
+    BOOL            bResult;
+    E_UINT32        cb;
+
+    reg.reg_EAX     = 0x440D;
+    reg.reg_ECX     = 0x484A;
+    reg.reg_EBX     = pwInfo->m_iVolume | (iLockLevel << 8);
+    reg.reg_EDX     = iPermissions;
+    reg.reg_Flags   = 1;
+
+    bResult = DeviceIoControl(pwInfo->m_hVolume, VWIN32_DIOC_DOS_IOCTL,
+                              &reg, sizeof(reg), &reg,
+                              sizeof(reg), &cb, 0);
+
+    if (!bResult || bitSet(reg.reg_Flags, CARRY_FLAG)) {
+        return DISK_FAILURE;
+    }
+
+    return DISK_SUCCESS;
+}
+
+static DISKERROR
+unlockVolume_FAT32(wfeInfo *pwInfo)
+{
+    // mov ax, 440Dh      ; generic IOCTL
+    // mov bl, DriveNum   ; Drive to lock. 0 for default, 1 for A,...
+    // mov ch, DeviceCat  ; 48h for FAT32 drive
+    // mov cl, 6Ah        ; Unlock Logical Volume
+    // int 21h
+    //
+    // jc error_handler
+
+    DIOC_REGISTERS  reg;
+    BOOL            bResult;
+    E_UINT32        cb;
+
+    reg.reg_EAX     = 0x440D;
+    reg.reg_ECX     = 0x486A;
+    reg.reg_EBX     = pwInfo->m_iVolume;
+    reg.reg_Flags   = 1;
+
+    bResult = DeviceIoControl(pwInfo->m_hVolume, VWIN32_DIOC_DOS_IOCTL,
+                              &reg, sizeof(reg), &reg,
+                              sizeof(reg), &cb, 0);
+
+    if (!bResult || bitSet(reg.reg_Flags, CARRY_FLAG)) {
+        return DISK_FAILURE;
+    }
+
+    return DISK_SUCCESS;
+}
+
+static inline E_UINT32
+item_FAT32(E_PUINT8 pBuffer, E_UINT32 uIndex)
+{
+    return (0x0FFFFFFF & *((E_UINT32*)&pBuffer[uIndex * 32 / 8]));
+}
+
+static inline void
+getInfo_FAT32(wfeInfo *pwInfo, E_PUINT8 pBuffer)
+{
+    try {
+        BOOTSECTOR32 *bs32 = (BOOTSECTOR32*)pBuffer;
+
+        pwInfo->m_uSectorsPerCluster = bs32->bpb.A_BF_BPB_SectorsPerCluster;
+        pwInfo->m_uSectorSize        = bs32->bpb.A_BF_BPB_BytesPerSector;
+        pwInfo->m_uSectorsPerFAT     = (E_UINT16)((bs32->bpb.A_BF_BPB_BigSectorsPerFatHi << 16) +
+                                                 bs32->bpb.A_BF_BPB_BigSectorsPerFat);
+        pwInfo->m_uReservedSectors   = bs32->bpb.A_BF_BPB_ReservedSectors;
+        pwInfo->m_uSectorsTotal      = bs32->bpb.A_BF_BPB_TotalSectors;
+        if (pwInfo->m_uSectorsTotal == 0) {
+            pwInfo->m_uSectorsTotal  = (bs32->bpb.A_BF_BPB_BigTotalSectorsHigh << 16) +
+                                       bs32->bpb.A_BF_BPB_BigTotalSectors;
+        }
+        pwInfo->m_uFATDirectoryStart = (bs32->bpb.A_BF_BPB_RootDirStrtClusHi << 16) +
+                                       bs32->bpb.A_BF_BPB_RootDirStrtClus;
+        pwInfo->m_uStartSector       = pwInfo->m_uReservedSectors +
+                                       pwInfo->m_uSectorsPerFAT * bs32->bpb.A_BF_BPB_NumberOfFATs;
+    } catch (...) {
+        ASSERT(0);
+    }
+}
+
+
+// FAT specific functions
+//
+static DISKERROR
+readSectors_FAT(wfeInfo *pwInfo, E_UINT32 uStartSector, E_UINT16 uSectors, E_PUINT8 pBuffer)
+{
+    // int 25h                          ; Absolute disk read
+    //
+    // al = logical drive number        ; 0 = A:, 1 = B:, ...
+    // bx = pointer to data buffer
+    //      pointer to control block
+    // cx = number of sectors to
+    //      read, -1 if bx is control
+    //      block
+
+    DIOC_REGISTERS  reg;
+    DISKIO          di;
+    BOOL            bResult;
+    E_UINT32        cb;
+
+    reg.reg_EAX      = pwInfo->m_iVolume - 1;
+    reg.reg_EBX      = (E_UINT32)&di;
+    reg.reg_ECX      = 0xFFFF;
+    reg.reg_Flags    = 1;
+
+    // control block
+    di.diStartSector = uStartSector;
+    di.diSectors     = uSectors;
+    di.diBuffer      = (E_UINT32)pBuffer;
+
+    bResult = DeviceIoControl(pwInfo->m_hVolume, VWIN32_DIOC_DOS_INT25,
+              &reg, sizeof(reg), &reg, sizeof(reg), &cb, 0);
+
+    if (!bResult || bitSet(reg.reg_Flags, CARRY_FLAG)) {
+        return DISK_FAILURE;
+    }
+
+    return DISK_SUCCESS;
+}
+
+static DISKERROR
+writeSectors_FAT(wfeInfo *pwInfo, E_UINT32 uStartSector, E_UINT16 uSectors, E_PUINT8 pBuffer)
+{
+    // int 26h                          ; Absolute disk write
+    //
+    // al = logical drive number        ; 0 = A:, 1 = B:, ...
+    // bx = pointer to data buffer
+    //      pointer to control block
+    // cx = number of sectors to
+    //      read, -1 if bx is control
+    //      block
+
+    BOOL            bResult;
+    E_UINT32        cb;
+    DIOC_REGISTERS  reg;
+    DISKIO          di;
+
+    reg.reg_EAX         = pwInfo->m_iVolume - 1;
+    reg.reg_EBX         = (E_UINT32)&di;
+    reg.reg_ECX         = 0xFFFF;
+    reg.reg_Flags       = 1;
+
+    // control block
+
+    di.diStartSector    = uStartSector;
+    di.diSectors        = uSectors;
+    di.diBuffer         = (E_UINT32)pBuffer;
+
+    bResult = DeviceIoControl(pwInfo->m_hVolume, VWIN32_DIOC_DOS_INT26,
+                              &reg, sizeof(reg), &reg,
+                              sizeof(reg), &cb, 0);
+
+    if (!bResult || bitSet(reg.reg_Flags, CARRY_FLAG)) {
+        return DISK_FAILURE;
+    }
+
+    return DISK_SUCCESS;
+}
+
+static DISKERROR
+lockState_FAT(wfeInfo *pwInfo)
+{
+    // mov ax, 440Dh        ; generic IOCTL
+    // mov bl, DriveNum     ; Drive to poll. 1-based.
+    // mov ch, DeviceCat    ; 08h for FAT drive
+    // mov cl, 6Ch          ; Get Lock Flag State
+    // int 21h
+    //
+    // jc error_handler
+    // mov [AccessFlag], ax  ; state of access flag
+
+    DIOC_REGISTERS  reg;
+    BOOL            bResult;
+    E_UINT32        cb;
+
+    reg.reg_EAX     = 0x440D;
+    reg.reg_ECX     = 0x086c;
+    reg.reg_EBX     = pwInfo->m_iVolume;
+    reg.reg_Flags   = 1;
+
+    bResult = DeviceIoControl(pwInfo->m_hVolume, VWIN32_DIOC_DOS_IOCTL,
+                              &reg, sizeof(reg), &reg,
+                              sizeof(reg), &cb, 0);
+
+    if (!bResult || bitSet(reg.reg_Flags, CARRY_FLAG)) {
+        return DISK_FAILURE;
+    }
+
+    return ((reg.reg_EAX == 0) ? DISK_NOP : DISK_WRITE);
+}
+
+static DISKERROR
+lockVolume_FAT(wfeInfo *pwInfo, E_INT32 iLockLevel, E_INT32 iPermissions)
+{
+    // mov ax, 440Dh        ; generic IOCTL
+    // mov bh, LockLevel    ; Level of the lock. 0, 1, 2 or 3
+    // mov bl, DriveNum     ; Drive to lock. 0 for default, 1 for A,...
+    // mov ch, DeviceCat    ; 48h for FAT32 drive, 08h for FAT drive
+    // mov cl, 4Ah          ; Lock Logical Volume
+    // mov dx, Permissions  ; Bit  Meaning
+    //                        0    0 = Write operations are failed
+    //                        0    1 = Write operations are allowed
+    //                        1    0 = New file mapping are allowed
+    //                        1    1 = New file mapping are failed
+    //                        2    1 = The volume is locked for formatting
+    //                                 (specified when a level 0 lock is
+    //                                  obtained for the second time).
+    // int 21h
+    //
+    // jc error_handler
+
+    DIOC_REGISTERS  reg;
+    BOOL            bResult;
+    E_UINT32        cb;
+
+    reg.reg_EAX     = 0x440D;
+    reg.reg_ECX     = 0x084A;
+    reg.reg_EBX     = pwInfo->m_iVolume | (iLockLevel << 8);
+    reg.reg_EDX     = iPermissions;
+    reg.reg_Flags   = 1;
+
+    bResult = DeviceIoControl(pwInfo->m_hVolume, VWIN32_DIOC_DOS_IOCTL,
+                              &reg, sizeof(reg), &reg,
+                              sizeof(reg), &cb, 0);
+
+    if (!bResult || bitSet(reg.reg_Flags, CARRY_FLAG)) {
+        return DISK_FAILURE;
+    }
+
+    return DISK_SUCCESS;
+}
+
+static DISKERROR
+unlockVolume_FAT(wfeInfo *pwInfo)
+{
+    // mov ax, 440Dh      ; generic IOCTL
+    // mov bl, DriveNum   ; Drive to lock. 0 for default, 1 for A,...
+    // mov ch, DeviceCat  ; 48h for FAT32 drive, 08h for FAT drive
+    // mov cl, 6Ah        ; Unlock Logical Volume
+    // int 21h
+    //
+    // jc error_handler
+
+    DIOC_REGISTERS  reg;
+    BOOL            bResult;
+    E_UINT32        cb;
+
+    reg.reg_EAX     = 0x440D;
+    reg.reg_ECX     = 0x086A;
+    reg.reg_EBX     = pwInfo->m_iVolume;
+    reg.reg_Flags   = 1;
+
+    bResult = DeviceIoControl(pwInfo->m_hVolume, VWIN32_DIOC_DOS_IOCTL,
+                              &reg, sizeof(reg), &reg,
+                              sizeof(reg), &cb, 0);
+
+    if (!bResult || bitSet(reg.reg_Flags, CARRY_FLAG)) {
+        return DISK_FAILURE;
+    }
+
+    return DISK_SUCCESS;
+}
+
+static DISKERROR
+lockDirectory_FAT(wfeInfo*, LPCTSTR)
+{
+    // not supported
+    return DISK_FAILURE;
+}
+
+static DISKERROR
+unlockDirectory_FAT(wfeInfo*)
+{
+    // not supported
+    return DISK_FAILURE;
+}
+
+static inline E_UINT32
+item_FAT16(E_PUINT8 pBuffer, E_UINT32 uIndex)
+{
+    return ((E_UINT32)*((E_PUINT16)&pBuffer[uIndex * 16 / 8]));
+}
+
+static inline E_UINT32
+item_FAT12(E_PUINT8 pBuffer, E_UINT32 uIndex)
+{
+    E_UINT32  uValue;
+    E_PUINT16 pwFAT = (E_PUINT16)(&pBuffer[uIndex * 12 / 8]);
+
+    if (uIndex & 1) {
+        uValue = (E_UINT32)(*pwFAT >> 4);
+    } else {
+        uValue = (E_UINT32)(0x0FFF & *pwFAT);
+    }
+
+    return uValue;
+}
+
+static inline void
+getInfo_FAT(wfeInfo *pwInfo, E_PUINT8 pBuffer)
+{
+    try {
+        BOOTSECTOR *bs = (BOOTSECTOR*)pBuffer;
+
+        pwInfo->m_uSectorsPerCluster = bs->bsSecPerClust;
+        pwInfo->m_uSectorSize        = bs->bsBytesPerSec;
+        pwInfo->m_uSectorsPerFAT     = bs->bsFATsecs;
+        pwInfo->m_uReservedSectors   = bs->bsResSectors;
+        pwInfo->m_uSectorsTotal      = bs->bsSectors;
+        if (pwInfo->m_uSectorsTotal == 0) {
+            pwInfo->m_uSectorsTotal  = bs->bsHugeSectors;
+        }
+        pwInfo->m_uFATDirectorySize  = (E_UINT16)((32 * bs->bsRootDirEnts +
+                                                  pwInfo->m_uSectorSize - 1) / pwInfo->m_uSectorSize);
+        pwInfo->m_uFATDirectoryStart = pwInfo->m_uReservedSectors +
+                                       pwInfo->m_uSectorsPerFAT * bs->bsFATs;
+        pwInfo->m_uStartSector       = pwInfo->m_uFATDirectoryStart + pwInfo->m_uFATDirectorySize;
+    } catch (...) {
+        ASSERT(0);
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// common read/write functions
+
+static inline E_UINT32
+readSectors(wfeInfo *pwInfo, E_UINT32 uStartSector, E_UINT16 uSectors, E_PUINT8 pBuffer)
+{
+    try {
+        if (pwInfo->FS.readSectors(pwInfo, uStartSector, uSectors, pBuffer) == DISK_SUCCESS) {
+            return WFE_SUCCESS;
+        }
+    } catch (...) {
+        ASSERT(0);
+    }
+
+    return WFE_FAILURE;
+}
+
+static E_UINT32
+writeSectors(wfeInfo *pwInfo, E_UINT32 uStartSector, E_UINT16 uSectors, E_PUINT8 pBuffer)
+{
+    try {
+        E_UINT32 uReturn = WFE_FAILURE;
+
+        if (pwInfo->FS.lockVolume(pwInfo, LEVEL2_LOCK, 0) == DISK_SUCCESS) {
+            if (pwInfo->FS.lockVolume(pwInfo, LEVEL3_LOCK, 0) == DISK_SUCCESS) {
+                if (pwInfo->FS.lockState(pwInfo) != DISK_NOP) {
+                    uReturn = WFE_DISKMODIFIED;
+                } else {
+                    if (pwInfo->FS.writeSectors(pwInfo, uStartSector, uSectors, pBuffer) == DISK_SUCCESS) {
+                        uReturn = WFE_SUCCESS;
+                    }
+                }
+                pwInfo->FS.unlockVolume(pwInfo);
+            }
+            pwInfo->FS.unlockVolume(pwInfo);
+        }
+
+        return uReturn;
+    } catch (...) {
+        ASSERT(0);
+    }
+
+    return WFE_FAILURE;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// common FAT functions
+
+static inline BOOL
+verifyFAT(wfeInfo *pwInfo)
+{
+    E_UINT32 uClusterValue;
+    E_UINT32 uIndex;
+
+    try {
+        // two is the first valid cluster
+        for (uIndex = 2; uIndex < pwInfo->m_uClustersTotal; uIndex++) {
+            uClusterValue = pwInfo->FS.item(pwInfo->m_pFAT, uIndex);
+
+            // check for valid cluster number, if it is not between
+            // uFSLowValue and uFSHighValue, it must be smaller than
+            // the number of total clusters
+
+            if (!((uClusterValue >= pwInfo->FS.uLowValue &&
+                   uClusterValue <= pwInfo->FS.uHighValue) ||
+                  (uClusterValue <= pwInfo->m_uClustersTotal))) {
+                return FALSE;
+            }
+        }
+
+        return TRUE;
+    } catch (...) {
+        ASSERT(0);
+    }
+
+    return FALSE;
+}
+
+static E_UINT32
+readFAT(wfeInfo *pwInfo)
+{
+    try {
+        E_UINT32 uReturn     = WFE_FAILURE;
+        E_UINT32 uBufferSize = pwInfo->m_uSectorSize *
+                               pwInfo->m_uSectorsPerFAT;
+
+        pwInfo->m_pFAT = new E_UINT8[uBufferSize];
+        ZeroMemory(pwInfo->m_pFAT, uBufferSize);
+
+        uReturn = readSectors(pwInfo, pwInfo->m_uReservedSectors,
+                              pwInfo->m_uSectorsPerFAT,
+                              pwInfo->m_pFAT);
+
+        if (uReturn == WFE_SUCCESS) {
+            if (!verifyFAT(pwInfo)) {
+                uReturn = WFE_FATERROR;
+            }
+        }
+
+        if (uReturn != WFE_SUCCESS) {
+            delete[] pwInfo->m_pFAT;
+            pwInfo->m_pFAT = 0;
+        }
+
+        return uReturn;
+    } catch (...) {
+        ASSERT(0);
+    }
+
+    return WFE_FAILURE;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// common functions
+
+static inline bool
+isExactMatchingFolder(CEraserContext *context, const CString& strFolder)
+{
+    try {
+        if (context->m_pstrlDirectories) {
+            return (context->m_pstrlDirectories->Find(strFolder) != NULL);
+        }
+    } catch (...) {
+        ASSERT(0);
+    }
+
+    return true;
+}
+
+static inline bool
+isMatchingFolder(CEraserContext *context, const CString& strFolder)
+{
+    try {
+        if (context->m_pstrlDirectories) {
+            // see if given folder is in the list
+            CString strItem;
+            E_INT32 iLength = strFolder.GetLength();
+            POSITION pos = context->m_pstrlDirectories->GetHeadPosition();
+
+            while (pos != NULL) {
+                strItem = context->m_pstrlDirectories->GetNext(pos);
+                if (strncmp((LPCTSTR)strItem, (LPCTSTR)strFolder, iLength) == 0) {
+                    return true;
+                }
+            }
+
+            return false;
+        }
+    } catch (...) {
+        ASSERT(0);
+    }
+
+    return true;
+}
+
+static E_UINT32
+clearDeletedEntries(wfeInfo *pwInfo, CEraserContext *context, E_PUINT8 pEntry, E_UINT32 uSize, const CString& strBase)
+{
+    E_UINT32  uReturn = WFE_SUCCESS;
+    E_PUINT8  pEnd      = pEntry + uSize;
+    PDIRENTRY pd        = 0;
+    TCHAR     szDeName[9];
+    TCHAR     szDeExtension[4];
+    CString   strExtension;
+    DIRINFO   diInfo;
+
+    try {
+        szDeName[8] = 0;
+        szDeExtension[3] = 0;
+
+        while (pEntry < pEnd) {
+            pd = (PDIRENTRY)pEntry;
+
+            if (pd->deName[0] == 0) {
+                // filename is not used
+            } else if (pd->deName[0] == 0xE5) {
+                // deleted entry
+                ZeroMemory(&(pEntry[1]), sizeof(DIRENTRY) - 1);
+                uReturn = WFE_CHANGED;
+            } else if (((PLONGDIRENTRY)pd)->leAttributes == 0xF) {
+                // long entry
+            } else if (bitSet(pd->deAttributes, 0x10)) {
+                // directory
+                if (strncmp(".       ", (LPCTSTR)pd->deName, 8) != 0 &&
+                    strncmp("..      ", (LPCTSTR)pd->deName, 8) != 0) {
+
+                    strncpy(szDeName, (LPCTSTR)pd->deName, 8);
+                    strncpy(szDeExtension, (LPCTSTR)pd->deExtension, 3);
+
+                    diInfo.strPath = strBase + szDeName;
+                    diInfo.strPath.TrimRight();
+
+                    strExtension = szDeExtension;
+                    strExtension.TrimRight();
+
+                    if (!strExtension.IsEmpty()) {
+                        diInfo.strPath += "." + strExtension;
+                    }
+
+                    diInfo.strPath += "\\";
+                    diInfo.strPath.MakeUpper();
+
+                    if (isMatchingFolder(context, diInfo.strPath)) {
+                        // subdirectory - store on stack for later processing
+                        if (context->m_piCurrent.m_fsType != fsFAT32) {
+                            diInfo.uCluster = ((E_UINT32)pd->deStartCluster) & 0xFFFFF;
+                        } else {
+                            diInfo.uCluster = ((E_UINT32)pd->deEAhandle) & 0xFFFF;
+                            diInfo.uCluster <<= 16;
+                            diInfo.uCluster |= ((E_UINT32)pd->deStartCluster) & 0xFFFF;
+                        }
+                        pwInfo->m_stDirectories.Push(diInfo);
+                    }
+                }
+            }
+
+            pEntry += sizeof(DIRENTRY);
+        }
+
+        // we must keep trailing zero to show end of directory,
+        // unless of course cluster is completely full
+        pEntry++;
+
+        // clear off slack at end of directory chain unless full
+        if (pEntry < pEnd) {
+            ZeroMemory(pEntry, pEnd - pEntry);
+        }
+
+        return uReturn;
+    } catch (CException *e) {
+        handleException(e, context);
+    } catch (...) {
+        ASSERT(0);
+    }
+
+    return WFE_FAILURE;
+}
+
+static inline E_UINT32
+getBufferSize(wfeInfo *pwInfo, E_UINT32 uIndexCluster, E_UINT32& uSize)
+{
+    try {
+        uSize = 0;
+
+        while (isClusterNotEnd(pwInfo, uIndexCluster)) {
+            uSize += pwInfo->m_uClusterSize;
+            uIndexCluster = pwInfo->FS.item(pwInfo->m_pFAT, uIndexCluster);
+        }
+
+        if (isClusterError(pwInfo, uIndexCluster) || uSize == 0) {
+            return WFE_FAILURE;
+        }
+
+        return WFE_SUCCESS;
+    } catch (...) {
+        ASSERT(0);
+    }
+
+    return WFE_FAILURE;
+}
+
+static E_UINT32
+readEntry(wfeInfo *pwInfo, E_UINT32 uIndexCluster, E_PUINT8 pBuffer)
+{
+    E_UINT32 uIndexBuffer = 0;
+    E_UINT32 uReturn      = WFE_SUCCESS;
+
+    try {
+        while (isClusterNotEnd(pwInfo, uIndexCluster)) {
+            uReturn = readSectors(pwInfo,
+                                  clusterToSector(pwInfo, uIndexCluster),
+                                  pwInfo->m_uSectorsPerCluster,
+                                  &(pBuffer[uIndexBuffer]));
+
+            if (uReturn != WFE_SUCCESS) {
+                break;
+            }
+
+            uIndexBuffer += pwInfo->m_uClusterSize;
+            uIndexCluster = pwInfo->FS.item(pwInfo->m_pFAT, uIndexCluster);
+        }
+    } catch (...) {
+        ASSERT(0);
+        uReturn = WFE_FAILURE;
+    }
+
+    return uReturn;
+}
+
+static E_UINT32
+writeEntry(wfeInfo *pwInfo, E_UINT32 uIndexCluster, E_PUINT8 pBuffer)
+{
+    E_UINT32 uIndexBuffer = 0;
+    E_UINT32 uReturn = WFE_SUCCESS;
+
+    try {
+        while (isClusterNotEnd(pwInfo, uIndexCluster)) {
+            uReturn = writeSectors(pwInfo,
+                                   clusterToSector(pwInfo, uIndexCluster),
+                                   pwInfo->m_uSectorsPerCluster,
+                                   &(pBuffer[uIndexBuffer]));
+
+            if (uReturn != WFE_SUCCESS) {
+                break;
+            }
+
+            uIndexBuffer += pwInfo->m_uClusterSize;
+            uIndexCluster = pwInfo->FS.item(pwInfo->m_pFAT, uIndexCluster);
+        }
+    } catch (...) {
+        ASSERT(0);
+        uReturn = WFE_FAILURE;
+    }
+
+    return uReturn;
+}
+
+static E_UINT32
+clearEntries(wfeInfo *pwInfo, CEraserContext *context)
+{
+    E_UINT32 uReturn     = WFE_SUCCESS;
+    E_UINT32 uBufferSize = 0;
+    E_PUINT8 pBuffer     = 0;
+    DIRINFO  diInfo;
+    CString  strDirectory;
+    CString  strError;
+
+    try {
+        // reset progress
+        context->m_uProgressWipedFiles = 0;
+
+        if (context->m_piCurrent.m_fsType != fsFAT32) {
+            // the non-standard FAT16/FAT12 root directory must be handled separately
+            uBufferSize = pwInfo->m_uFATDirectorySize * pwInfo->m_uSectorSize;
+
+            pBuffer = new E_UINT8[uBufferSize];
+            ZeroMemory(pBuffer, uBufferSize);
+
+            uReturn = readSectors(pwInfo, pwInfo->m_uFATDirectoryStart,
+                                  pwInfo->m_uFATDirectorySize, pBuffer);
+
+            if (uReturn == WFE_SUCCESS) {
+                uReturn = clearDeletedEntries(pwInfo, context, pBuffer, uBufferSize, "\\");
+
+                if (uReturn == WFE_CHANGED && isExactMatchingFolder(context, "\\")) {
+                    uReturn = writeSectors(pwInfo, pwInfo->m_uFATDirectoryStart,
+                                           pwInfo->m_uFATDirectorySize, pBuffer);
+                }
+            }
+
+            delete[] pBuffer;
+            pBuffer = 0;
+
+            // progress information
+            context->m_uProgressWipedFiles++;
+            if (context->m_uProgressFolders > 0) {
+                eraserSafeAssign(context, context->m_uProgressPercent,
+                    (E_UINT8)((context->m_uProgressWipedFiles * 100) / context->m_uProgressFolders));
+            }
+
+            eraserUpdateNotify(context);
+        } else {
+            // the FAT32 root directory can be handled like any other directory
+            diInfo.uCluster = pwInfo->m_uFATDirectoryStart;
+            diInfo.strPath = "\\";
+
+            pwInfo->m_stDirectories.Push(diInfo);
+        }
+
+        while (pwInfo->m_stDirectories.Pop(&diInfo) && (uReturn == WFE_SUCCESS || uReturn == WFE_CHANGED)) {
+
+            if (eraserInternalTerminated(context) || !isClusterNotEnd(pwInfo, diInfo.uCluster)) {
+                return WFE_FAILURE;
+            }
+
+            if (isWindowsNT && !isEntryLocked(pwInfo)) {
+                strDirectory.Format("%c:%s", (TCHAR)(pwInfo->m_iVolume + 'A' - 1), (LPCTSTR)diInfo.strPath);
+                pwInfo->FS.lockDirectory(pwInfo, (LPCTSTR)strDirectory);
+            }
+
+            uReturn = getBufferSize(pwInfo, diInfo.uCluster, uBufferSize);
+
+            if (uReturn == WFE_SUCCESS) {
+                pBuffer = new E_UINT8[uBufferSize];
+                ZeroMemory(pBuffer, uBufferSize);
+
+                uReturn = readEntry(pwInfo, diInfo.uCluster, pBuffer);
+
+                if (uReturn == WFE_SUCCESS) {
+                    uReturn = clearDeletedEntries(pwInfo, context, pBuffer, uBufferSize, diInfo.strPath);
+
+                    if (uReturn == WFE_CHANGED && isExactMatchingFolder(context, diInfo.strPath)) {
+                        if (isWindowsNT && !isEntryLocked(pwInfo)) {
+                            eraserAddError1(context, IDS_ERROR_DIRENTRIES_LOCK, (LPCTSTR)strDirectory);
+                        } else {
+                            uReturn = writeEntry(pwInfo, diInfo.uCluster, pBuffer);
+                        }
+                    }
+                }
+
+                delete[] pBuffer;
+                pBuffer = 0;
+            }
+
+            if (isWindowsNT) {
+                pwInfo->FS.unlockDirectory(pwInfo);
+            }
+
+            // progress information
+            context->m_uProgressWipedFiles++;
+            if (context->m_uProgressFolders > 0) {
+                eraserSafeAssign(context, context->m_uProgressPercent,
+                    (E_UINT8)((context->m_uProgressWipedFiles * 100) / context->m_uProgressFolders));
+            }
+            setTotalProgress(context);
+
+            eraserUpdateNotify(context);
+        }
+    } catch (CException *e) {
+        handleException(e, context);
+        uReturn = WFE_FAILURE;
+    } catch (...) {
+        ASSERT(0);
+        uReturn = WFE_FAILURE;
+    }
+
+    return uReturn;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// initialize file system specific read & write functions
+
+static void
+initReadWrite(wfeInfo *pwInfo, PARTITIONINFO& pi)
+{
+    try {
+        if (isWindowsNT) {
+            pwInfo->FS.readSectors     = readSectors_NT;
+            pwInfo->FS.writeSectors    = writeSectors_NT;
+            pwInfo->FS.lockVolume      = lockVolume_NT;
+            pwInfo->FS.unlockVolume    = unlockVolume_NT;
+            pwInfo->FS.lockState       = lockState_NT;
+            pwInfo->FS.unlockDirectory = unlockDirectory_NT;
+            pwInfo->FS.lockDirectory   = lockDirectory_NT;
+            if (pi.m_fsType == fsFAT32) {
+                pwInfo->FS.getInfo     = getInfo_FAT32;
+            } else {
+                pwInfo->FS.getInfo     = getInfo_FAT;
+            }
+        } else {
+            if (pi.m_fsType == fsFAT32) {
+                pwInfo->FS.readSectors     = readSectors_FAT32;
+                pwInfo->FS.writeSectors    = writeSectors_FAT32;
+                pwInfo->FS.lockVolume      = lockVolume_FAT32;
+                pwInfo->FS.unlockVolume    = unlockVolume_FAT32;
+                pwInfo->FS.lockState       = lockState_FAT32;
+                pwInfo->FS.unlockDirectory = unlockDirectory_FAT;
+                pwInfo->FS.lockDirectory   = lockDirectory_FAT;
+                pwInfo->FS.getInfo         = getInfo_FAT32;
+            } else {
+                pwInfo->FS.readSectors     = readSectors_FAT;
+                pwInfo->FS.writeSectors    = writeSectors_FAT;
+                pwInfo->FS.lockVolume      = lockVolume_FAT;
+                pwInfo->FS.unlockVolume    = unlockVolume_FAT;
+                pwInfo->FS.lockState       = lockState_FAT;
+                pwInfo->FS.unlockDirectory = unlockDirectory_FAT;
+                pwInfo->FS.lockDirectory   = lockDirectory_FAT;
+                pwInfo->FS.getInfo         = getInfo_FAT;
+            }
+        }
+        pwInfo->m_uSectorSize = DEFAULT_SECTOR_SIZE;
+    } catch (...) {
+        ASSERT(0);
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// initialize file system information and other specific stuff
+
+static void
+initFileSystemInfo(wfeInfo *pwInfo, PARTITIONINFO& pi)
+{
+    try {
+        // information
+        if (pwInfo->m_uSectorsPerCluster == 0) {
+            pwInfo->m_uClustersTotal = 0;
+        } else {
+            pwInfo->m_uClustersTotal = (pwInfo->m_uSectorsTotal - pwInfo->m_uStartSector) /
+                                       pwInfo->m_uSectorsPerCluster;
+        }
+
+        pwInfo->m_uClusterSize = pwInfo->m_uSectorsPerCluster * pwInfo->m_uSectorSize;
+
+        // FAT type
+        if (pi.m_fsType == fsFAT) {
+            if (pwInfo->m_uClustersTotal <= FAT12_MAX_CLUSTERS) {
+                pi.m_fsType = fsFAT12;
+            } else {
+                pi.m_fsType = fsFAT16;
+            }
+        }
+
+        // specific
+        if (pi.m_fsType == fsFAT32) {
+            pwInfo->FS.item         = item_FAT32;
+            pwInfo->FS.uHighValue   = FAT32_MAX_VALUE;
+            pwInfo->FS.uLowValue    = FAT32_MAX_CLUSTERS;
+            pwInfo->FS.uErrorValue  = FAT32_MAX_ERROR;
+        } else if (pi.m_fsType == fsFAT16) {
+            pwInfo->FS.item         = item_FAT16;
+            pwInfo->FS.uHighValue   = FAT16_MAX_VALUE;
+            pwInfo->FS.uLowValue    = FAT16_MAX_CLUSTERS;
+            pwInfo->FS.uErrorValue  = FAT16_MAX_ERROR;
+        } else {
+            pwInfo->FS.item         = item_FAT12;
+            pwInfo->FS.uHighValue   = FAT12_MAX_VALUE;
+            pwInfo->FS.uLowValue    = FAT12_MAX_CLUSTERS;
+            pwInfo->FS.uErrorValue  = FAT12_MAX_ERROR;
+        }
+    } catch (...) {
+        ASSERT(0);
+    }
+}
+
+static inline E_UINT32
+openVolume(wfeInfo& wfe, PARTITIONINFO& pi)
+{
+    if (!isFileSystemFAT(pi)) {
+        return WFE_NOT_SUPPORTED;
+    }
+
+    // one-based volume
+    wfe.m_iVolume = toupper(pi.m_szDrive[0]) - 'A' + 1;
+
+    if (wfe.m_hVolume != INVALID_HANDLE_VALUE) {
+        CloseHandle(wfe.m_hVolume);
+        wfe.m_hVolume = INVALID_HANDLE_VALUE;
+    }
+
+    if (isWindowsNT) {
+        TCHAR szVolume[] = "\\\\.\\ :";
+        szVolume[4] = pi.m_szDrive[0];
+
+        wfe.m_hVolume = CreateFile(szVolume, GENERIC_READ | GENERIC_WRITE,
+                                   FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
+                                   OPEN_EXISTING, FILE_FLAG_NO_BUFFERING,
+                                   NULL);
+    } else {
+        wfe.m_hVolume = CreateFile(szVWIN32, 0, 0, NULL, 0,
+                                   FILE_FLAG_DELETE_ON_CLOSE, NULL);
+    }
+
+    if (wfe.m_hVolume != INVALID_HANDLE_VALUE) {
+        return WFE_SUCCESS;
+    } else {
+        return WFE_FAILURE;
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// functions exported from module
+
+bool
+getFATClusterAndSectorSize(LPCTSTR szDrive, E_UINT32& uCluster, E_UINT32& uSector)
+{
+    E_PUINT8 pBuffer = 0;
+
+    uCluster = 0;
+    uSector = DEFAULT_SECTOR_SIZE;
+
+    try {
+        PARTITIONINFO pi;
+        wfeInfo wfe;
+
+        pi.m_szDrive[0] = szDrive[0];
+
+        if (!getPartitionType(pi)) {
+            return false;
+        }
+
+        if (openVolume(wfe, pi) == WFE_SUCCESS) {
+            bool bResult = false;
+
+            pBuffer = new E_UINT8[MAX_SECTOR_BUFFER];
+            ZeroMemory(pBuffer, MAX_SECTOR_BUFFER);
+
+            // init read & write for the file system
+            initReadWrite(&wfe, pi);
+
+            for (E_UINT32 uRestarts = 0; uRestarts < ERASER_MAXIMUM_RESTARTS; uRestarts++) {
+                bResult = (wfe.FS.lockVolume(&wfe, LEVEL1_LOCK, LOCK_MAX_PERMISSION) == DISK_SUCCESS);
+
+                if (bResult) {
+                    // read in the boot sector
+                    bResult = (readSectors(&wfe, 0, 1, pBuffer) == WFE_SUCCESS);
+
+                    wfe.FS.unlockVolume(&wfe);
+
+                    if (bResult) {
+                        // calculate cluster size
+                        if (pi.m_fsType == fsFAT32) {
+                            BOOTSECTOR32 *pbsBoot = (BOOTSECTOR32*)pBuffer;
+                            uSector = pbsBoot->bpb.A_BF_BPB_BytesPerSector;
+                            uCluster = uSector * pbsBoot->bpb.A_BF_BPB_SectorsPerCluster;
+                        } else {
+                            BOOTSECTOR *pbsBoot = (BOOTSECTOR*)pBuffer;
+                            uSector = pbsBoot->bsBytesPerSec;
+                            uCluster = uSector * pbsBoot->bsSecPerClust;
+                        }
+                    }
+
+                    break;
+                }
+
+                Sleep(0);
+            }
+
+            delete[] pBuffer;
+            pBuffer = 0;
+
+            return (bResult && uCluster > 0);
+        }
+    }
+    catch (...) {
+        ASSERT(0);
+        if (pBuffer) {
+            try {
+                delete[] pBuffer;
+            } catch (...) {
+            }
+            pBuffer = 0;
+        }
+    }
+
+    return false;
+}
+
+static E_UINT32
+wipeEntries(CEraserContext *context)
+{
+    try {
+        wfeInfo wfe;
+        E_UINT32 uResult = openVolume(wfe, context->m_piCurrent);
+
+        if (uResult == WFE_SUCCESS) {
+            E_PUINT8 pBuffer = new E_UINT8[MAX_SECTOR_BUFFER];
+            ZeroMemory(pBuffer, MAX_SECTOR_BUFFER);
+
+            // init read & write for the file system
+            initReadWrite(&wfe, context->m_piCurrent);
+
+            if (wfe.FS.lockVolume(&wfe, LEVEL1_LOCK, LOCK_MAX_PERMISSION) == DISK_SUCCESS) {
+                // read in the boot sector
+                if (readSectors(&wfe, 0, 1, pBuffer) == WFE_SUCCESS) {
+                    wfe.FS.getInfo(&wfe, pBuffer);
+                    initFileSystemInfo(&wfe, context->m_piCurrent);
+
+                    uResult = readFAT(&wfe);
+
+                    if (uResult == WFE_SUCCESS) {
+                        uResult = clearEntries(&wfe, context);
+                    }
+                }
+
+                wfe.FS.unlockVolume(&wfe);
+            }
+
+            delete[] pBuffer;
+            pBuffer = 0;
+        }
+
+        // done.
+        return uResult;
+    } catch (CException *e) {
+        handleException(e, context);
+    }
+
+    return WFE_FAILURE;
+}
+
+E_UINT32
+wipeFATFileEntries(CEraserContext *context, LPCTSTR szRetryMessage)
+{
+    E_UINT32 uError = WFE_SUCCESS;
+    E_UINT32 uRestart = 0;
+    bool     bStop = false;
+    CString  strMessage;
+
+    try {
+        do {
+            uRestart++;
+
+            // send the start message
+            eraserBeginNotify(context);
+
+            // wipe directory entries
+            uError = wipeEntries(context);
+
+            // if successful - great, if failed - not so great, if a
+            // write was detected - try again, up to cdwMaximumRestarts
+
+            switch (uError) {
+            case WFE_SUCCESS:
+                bStop = true;
+                break;
+            case WFE_DISKMODIFIED:
+                if (!eraserInternalTerminated(context)) {
+                    strMessage.Format(szRetryMessage, uRestart);
+                    eraserProgressSetMessage(context, strMessage);
+                    Sleep(0);
+                } else {
+                    bStop = true;
+                }
+                break;
+            default:
+                if (uError == WFE_NOT_SUPPORTED) {
+                    eraserAddError1(context, IDS_ERROR_DIRENTRIES_FS, (LPCTSTR)context->m_strData);
+                } else if (uError == WFE_FATERROR) {
+                    eraserAddError1(context, IDS_ERROR_DIRENTRIES_FAT, (LPCTSTR)context->m_strData);
+                } else {
+                    eraserAddError1(context, IDS_ERROR_DIRENTRIES, (LPCTSTR)context->m_strData);
+                }
+                bStop = true;
+                break;
+            }
+
+            if (!eraserInternalTerminated(context) && !bStop && uRestart == ERASER_MAXIMUM_RESTARTS) {
+                eraserAddError1(context, IDS_ERROR_DIRENTRIES_MAXRESTARTS, (LPCTSTR)context->m_strData);
+            }
+        } while (bStop == false && uRestart < ERASER_MAXIMUM_RESTARTS);
+
+        // add some entropy to the pool - how many times we needed
+        // to restart processing
+        randomAddEntropy((E_PUINT8)&uRestart, sizeof(E_PUINT8));
+
+        return uError;
+    } catch (CException *e) {
+        handleException(e, context);
+    }
+
+    return WFE_FAILURE;
+}
Index: /trunk/EraserDll/Stack.h
===================================================================
--- /trunk/EraserDll/Stack.h	(revision 4)
+++ /trunk/EraserDll/Stack.h	(revision 4)
@@ -0,0 +1,97 @@
+// Stack.h
+//
+// Eraser. Secure data removal. For Windows.
+// Copyright © 1997-2001  Sami Tolvanen (sami@tolvanen.com).
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#ifndef STACK_H
+#define STACK_H
+
+// template of a simple stack (LIFO = Last In First Out)
+
+template <class T> class CStack
+{
+public:
+    CStack();
+    ~CStack();
+
+    bool        Push(const T&);
+    bool        Pop(T*);
+
+    bool        IsEmpty();
+
+protected:
+    T           m_tValue;
+    CStack<T>   *m_psNext;
+};
+
+template <class T> CStack<T>::CStack() :
+m_psNext(0)
+{
+}
+
+template <class T> CStack<T>::~CStack()
+{
+    try {
+        if (m_psNext) {
+            delete m_psNext;
+            m_psNext = 0;
+        }
+    } catch (...) {
+    }
+}
+
+template <class T> bool CStack<T>::Push(const T& tValue)
+{
+    try {
+        CStack<T> *psNew = new CStack<T>();
+        psNew->m_tValue  = tValue;
+
+        psNew->m_psNext = m_psNext;
+        m_psNext = psNew;
+        return true;
+    } catch (...) {
+        return false;
+    }
+}
+
+template <class T> bool CStack<T>::Pop(T* ptValue)
+{
+    try {
+        if (ptValue && m_psNext) {
+            CStack<T> *psNext = m_psNext->m_psNext;
+
+            *ptValue = m_psNext->m_tValue;
+
+            m_psNext->m_psNext = 0;
+            delete m_psNext;
+
+            m_psNext = psNext;
+            return true;
+        }
+    } catch (...) {
+    }
+
+    return false;
+}
+
+template <class T> bool CStack<T>::IsEmpty()
+{
+    return (m_psNext != 0);
+}
+
+#endif
Index: /trunk/EraserDll/Tiger.cpp
===================================================================
--- /trunk/EraserDll/Tiger.cpp	(revision 4)
+++ /trunk/EraserDll/Tiger.cpp	(revision 4)
@@ -0,0 +1,273 @@
+// Tiger.cpp
+//
+// An implementation of Tiger/192 based on the reference code,
+// assumes little-endian architecture.
+//
+// Eraser. Secure data removal. For Windows.
+// Copyright © 1997-2001  Sami Tolvanen (sami@tolvanen.com).
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#include "stdafx.h"
+#include "EraserDll.h"
+#include "Tiger.h"
+
+/*
+** Word size
+*/
+
+#define ARCHITECTURE_WORDSIZE   32
+
+/*
+** Magic numbers
+*/
+
+#define I0      0x0123456789ABCDEF  /* Initialization values */
+#define I1      0xFEDCBA9876543210
+#define I2      0xF096A5B4C3B2E187
+#define KS1     0xA5A5A5A5A5A5A5A5  /* In key schedule */
+#define KS2     I0
+#define KSS1    19                  /* Shift values */
+#define KSS2    23
+#define M1      5                   /* Multiplicative constants for each pass */
+#define M2      7
+#define MN      9
+
+/*
+** S-boxes
+*/
+
+extern E_UINT64 table[4 * 256];
+
+#define T1 (table)
+#define T2 (table + 256)
+#define T3 (table + 256 * 2)
+#define T4 (table + 256 * 3)
+
+/*
+** The compression function
+*/
+
+#if ARCHITECTURE_WORDSIZE == 64
+    /* Return the ith byte of word */
+    #define IB64(x, i) \
+        ( ((x) >> ((i) << 3)) & 0xFF)
+    #define IB0(x)  IB64(x, 0)
+    #define IB1(x)  IB64(x, 1)
+    #define IB2(x)  IB64(x, 2)
+    #define IB3(x)  IB64(x, 3)
+    #define IB4(x)  IB64(x, 4)
+    #define IB5(x)  IB64(x, 5)
+    #define IB6(x)  IB64(x, 6)
+    #define IB7(x)  IB64(x, 7)
+#else
+    /* Do the same and avoid 64-bit operations */
+    #define IBL32(x, i) \
+        ((E_UINT8)(((E_UINT32)(x)) >> ((i) << 3)))
+    #define IBH32(x, i) \
+        ((E_UINT8)(((E_UINT32)((x) >> (4 << 3))) >> ((i - 4) << 3)))
+
+    #define IB0(x)  IBL32(x, 0)
+    #define IB1(x)  IBL32(x, 1)
+    #define IB2(x)  IBL32(x, 2)
+    #define IB3(x)  IBL32(x, 3)
+    #define IB4(x)  IBH32(x, 4)
+    #define IB5(x)  IBH32(x, 5)
+    #define IB6(x)  IBH32(x, 6)
+    #define IB7(x)  IBH32(x, 7)
+#endif
+
+#define saveState \
+    sa = A; \
+    sb = B; \
+    sc = C;
+
+#define round(A, B, C, D, M) \
+    C ^= D; \
+    A -= T1[IB0(C)] ^ T2[IB2(C)] ^ T3[IB4(C)] ^ T4[IB6(C)];  \
+    B += T4[IB1(C)] ^ T3[IB3(C)] ^ T2[IB5(C)] ^ T1[IB7(C)];  \
+    B *= M;
+
+#define pass(A, B, C, M) \
+    round(A, B, C, D0, M) \
+    round(B, C, A, D1, M) \
+    round(C, A, B, D2, M) \
+    round(A, B, C, D3, M) \
+    round(B, C, A, D4, M) \
+    round(C, A, B, D5, M) \
+    round(A, B, C, D6, M) \
+    round(B, C, A, D7, M)
+
+#define keySchedule \
+    D0 -= D7 ^ KS1; \
+    D1 ^= D0; \
+    D2 += D1; \
+    D3 -= D2 ^ ((~D1) << KSS1); \
+    D4 ^= D3; \
+    D5 += D4; \
+    D6 -= D5 ^ ((~D4) >> KSS2); \
+    D7 ^= D6; \
+    D0 += D7; \
+    D1 -= D0 ^ ((~D7) << KSS1); \
+    D2 ^= D1; \
+    D3 += D2; \
+    D4 -= D3 ^ ((~D2) >> KSS2); \
+    D5 ^= D4; \
+    D6 += D5; \
+    D7 -= D6 ^ KS2;
+
+#define feedForward \
+    A ^= sa; \
+    B -= sb; \
+    C += sc;
+
+#define compress \
+    saveState \
+    pass(A, B, C, M1) \
+    keySchedule \
+    pass(C, A, B, M2) \
+    keySchedule \
+    pass(B, C, A, MN) \
+    feedForward
+
+#define DECLARE_COMPRESS_VARIABLES \
+    E_UINT64 A, B, C; \
+    E_UINT64 D0, D1, D2, D3, D4, D5, D6, D7; \
+    E_UINT64 sa, sb, sc
+
+#define tiger_compress_macro(block, state) \
+{ \
+    A = state[0]; \
+    B = state[1]; \
+    C = state[2]; \
+\
+    D0 = block[0]; \
+    D1 = block[1]; \
+    D2 = block[2]; \
+    D3 = block[3]; \
+    D4 = block[4]; \
+    D5 = block[5]; \
+    D6 = block[6]; \
+    D7 = block[7]; \
+\
+    compress; \
+\
+    state[0] = A; \
+    state[1] = B; \
+    state[2] = C; \
+}
+
+/*
+** Exported functions
+*/
+
+void tiger_compress(E_PUINT64 block, E_PUINT64 state)
+{
+    DECLARE_COMPRESS_VARIABLES;
+    tiger_compress_macro(block, state);
+}
+
+void tiger(E_PUINT64 buffer, E_UINT64 length, E_PUINT64 state, E_PUINT8 work)
+{
+    /*
+    ** Use macro version of tiger_compress for speed
+    */
+
+    #define tiger_compress(str, state) \
+        tiger_compress_macro(((E_PUINT64)(str)), ((E_PUINT64)(state)))
+
+    /*
+    ** Variables
+    */
+
+    DECLARE_COMPRESS_VARIABLES;
+    E_UINT64 i, j;
+
+    /*
+    ** h0
+    */
+
+    state[0] = I0;
+    state[1] = I1;
+    state[2] = I2;
+
+    /*
+    ** Process all available 64-byte blocks
+    */
+
+    for (i = length; i >= 64; i -= 64) {
+        tiger_compress(buffer, state);
+        buffer += 8;
+    }
+
+    /*
+    ** Process remaining < 64 bytes
+    */
+
+    /*
+    ** Copy remaining data to work buffer (if any)
+    */
+
+    for (j = 0; j < i; j++) {
+        work[j] = ((E_PUINT8)buffer)[j];
+    }
+
+    /*
+    ** MD4-compliant padding, starts with single bit 1 followed by a
+    ** string of 0's and the message length in bits as a 64-byte word
+    */
+
+    work[j++] = 0x01;
+
+    for (; j & 7; j++) {
+        work[j] = 0;
+    }
+
+    if (j > 56) {
+        /*
+        ** Message length won't fit anymore, need to process another block
+        */
+
+        for(; j < 64; j++) {
+            work[j] = 0;
+        }
+
+        tiger_compress((E_PUINT64)work, state);
+        j = 0;
+    }
+
+    for (; j < 56; j++) {
+        work[j] = 0;
+    }
+
+    /*
+    ** Bit length
+    */
+
+    *((E_PUINT64)&work[56]) = length << 3;
+
+    /*
+    ** Final compress and we're done
+    */
+
+    tiger_compress((E_PUINT64)work, state);
+}
+
+void tiger(E_PUINT64 buffer, E_UINT64 length, E_PUINT64 state)
+{
+    E_UINT8 work[64];
+    tiger(buffer, length, state, work);
+}
Index: /trunk/EraserDll/FillMemoryWith.cpp
===================================================================
--- /trunk/EraserDll/FillMemoryWith.cpp	(revision 4)
+++ /trunk/EraserDll/FillMemoryWith.cpp	(revision 4)
@@ -0,0 +1,97 @@
+// FillMemoryWith.cpp
+//
+// Eraser. Secure data removal. For Windows.
+// Copyright © 1997-2001  Sami Tolvanen (sami@tolvanen.com).
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#include "stdafx.h"
+#include "EraserDll.h"
+#include "FillMemoryWith.h"
+#include <stdio.h>
+
+#define MAX_PATTERN_BYTES   3
+
+void
+FillMemoryWith(LPVOID destination, E_UINT32 bytes, E_UINT8 patternSize, ...)
+{
+    E_UINT8 patternBytes[MAX_PATTERN_BYTES];
+
+    // "the error checking"
+    if (destination == 0 || bytes == 0 ||
+        patternSize == 0 || patternSize > MAX_PATTERN_BYTES) {
+        ASSERT(0);
+        return;
+    }
+
+    // read parameters
+    va_list vlArgs;
+    va_start(vlArgs, patternSize);
+
+    for (E_UINT8 i = 0; i < patternSize; i++) {
+        patternBytes[i] = va_arg(vlArgs, E_UINT8);
+    }
+
+    va_end(vlArgs);
+
+    // fill memory block with desired string
+ /*   __asm {
+            mov     ecx, dword ptr destination  ; pointer to destination
+            mov     esi, bytes                  ; number of bytes to write
+            mov     dh, patternSize             ; pattern length (bytes)
+
+        Start:
+            mov     dl, dh
+            lea     eax, dword ptr patternBytes ; pattern
+
+        Inner:
+            mov     bl, byte ptr [eax]          ; copy to destination
+            inc     eax
+            dec     esi
+            mov     [ecx], bl
+
+            je      Done
+
+            inc     ecx
+            dec     dl
+
+            jne     Inner
+            jmp     Start
+        Done:
+    }
+*/
+    /* So I felt like playing a bit with inline assembly.
+       Oh well, in case someone needs this to be more portable... */
+
+      E_PUINT8 pattern;
+      E_UINT8  position;
+    Start:
+        pattern = patternBytes;
+        position = patternSize;
+    Inner:
+        *((E_PUINT8)destination) = *pattern++;
+        if (--bytes == 0)
+            goto Done;
+
+        destination = ((E_PUINT8)destination) + 1;
+
+        if (--position > 0)
+            goto Inner;
+
+        goto Start;
+    Done:
+        return;
+}
Index: /trunk/EraserDll/Gutmann.h
===================================================================
--- /trunk/EraserDll/Gutmann.h	(revision 4)
+++ /trunk/EraserDll/Gutmann.h	(revision 4)
@@ -0,0 +1,27 @@
+// Gutmann.h
+//
+// Eraser. Secure data removal. For Windows.
+// Copyright © 1997-2001  Sami Tolvanen (sami@tolvanen.com).
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#ifndef GUTMANN_H
+#define GUTMANN_H
+
+bool
+wipeFileWithGutmann(CEraserContext *context);
+
+#endif // GUTMANN_H
Index: /trunk/EraserDll/ByteEdit.h
===================================================================
--- /trunk/EraserDll/ByteEdit.h	(revision 4)
+++ /trunk/EraserDll/ByteEdit.h	(revision 4)
@@ -0,0 +1,73 @@
+// ByteEdit.h
+//
+// Eraser. Secure data removal. For Windows.
+// Copyright © 1997-2001  Sami Tolvanen (sami@tolvanen.com).
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+
+#if !defined(AFX_BYTEEDIT_H__2E652310_BC8C_11D3_82A0_000000000000__INCLUDED_)
+#define AFX_BYTEEDIT_H__2E652310_BC8C_11D3_82A0_000000000000__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+/////////////////////////////////////////////////////////////////////////////
+// CByteEdit window
+
+class  CByteEdit : public CEdit
+{
+// Construction
+public:
+    CByteEdit();
+
+// Attributes
+public:
+
+// Operations
+public:
+
+// Overrides
+    // ClassWizard generated virtual function overrides
+    //{{AFX_VIRTUAL(CByteEdit)
+    public:
+    virtual BOOL Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext = NULL);
+    //}}AFX_VIRTUAL
+
+// Implementation
+public:
+    void SetByte(BYTE);
+    BYTE GetByte();
+    virtual ~CByteEdit();
+
+    // Generated message map functions
+protected:
+    //{{AFX_MSG(CByteEdit)
+    afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags);
+    afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
+    afx_msg void OnRButtonDown(UINT nFlags, CPoint point);
+    //}}AFX_MSG
+
+    DECLARE_MESSAGE_MAP()
+};
+
+/////////////////////////////////////////////////////////////////////////////
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_BYTEEDIT_H__2E652310_BC8C_11D3_82A0_000000000000__INCLUDED_)
Index: /trunk/EraserDll/FirstLast2kb.h
===================================================================
--- /trunk/EraserDll/FirstLast2kb.h	(revision 4)
+++ /trunk/EraserDll/FirstLast2kb.h	(revision 4)
@@ -0,0 +1,4 @@
+#ifndef _FIRSTLAST2KB_H
+#define _FIRSTLAST2KB_H
+bool wipeFileWithFirstLast2kb(CEraserContext *context);
+#endif
Index: /trunk/EraserDll/File.cpp
===================================================================
--- /trunk/EraserDll/File.cpp	(revision 4)
+++ /trunk/EraserDll/File.cpp	(revision 4)
@@ -0,0 +1,263 @@
+// File.cpp
+//
+// Eraser. Secure data removal. For Windows.
+// Copyright © 1997-2001  Sami Tolvanen (sami@tolvanen.com).
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#include "stdafx.h"
+#include "resource.h"
+#include "EraserDll.h"
+#include "Common.h"
+#include "File.h"
+#include "NTFS.h"
+#include "io.h"
+
+
+static inline void
+formatError(CString& strError)
+{
+    strError.Empty();
+    if (GetLastError() != NO_ERROR) {
+        LPVOID lpMsgBuf;
+
+        FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+                      NULL,
+                      GetLastError(),
+                      MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+                      (LPTSTR) &lpMsgBuf,
+                      0,
+                      NULL);
+
+        strError = (LPCTSTR) lpMsgBuf;
+
+        // remove CRLFs
+        strError.TrimRight();
+        E_INT32 iPos = strError.Find("\r\n");
+
+        while (iPos != -1) {
+            strError = strError.Left(iPos) + " " +
+                       strError.Right(strError.GetLength() - iPos - 2);
+
+            iPos = strError.Find("\r\n");
+        }
+
+        // Free the buffer.
+        LocalFree(lpMsgBuf);
+    }
+}
+
+bool
+resetDate(HANDLE hFile)
+{
+    // changes all file dates to January 1st, 1980 0:00
+    SYSTEMTIME  stTime;
+    FILETIME    ftLocalTime;
+    FILETIME    ftTime;
+
+
+    stTime.wYear            = 1980;
+    stTime.wMonth           = 1;
+    stTime.wDayOfWeek       = 0;
+    stTime.wDay             = 1;
+    stTime.wHour            = 0;
+    stTime.wMinute          = 0;
+    stTime.wSecond          = 0;
+    stTime.wMilliseconds    = 0;
+    
+    return (SystemTimeToFileTime(&stTime, &ftLocalTime) &&
+            LocalFileTimeToFileTime(&ftLocalTime, &ftTime) &&
+            SetFileTime(hFile, &ftTime, &ftTime, &ftTime));
+}
+
+static inline bool
+wipeDataStreams(CEraserContext *context, DataStreamArray& streams)
+{
+    bool bResult = false;
+    E_INT32 lHigh = 0;
+    E_INT32 iSize = streams.GetSize();
+
+    for (E_INT32 i = 0; i < iSize; i++) {
+        context->m_hFile = CreateFile((LPCTSTR)streams[i].m_strName,
+                                      GENERIC_READ | GENERIC_WRITE,
+                                      (context->m_uTestMode) ? FILE_SHARE_READ | FILE_SHARE_WRITE : 0,
+                                      NULL,
+                                      OPEN_EXISTING,
+                                      FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING,
+                                      NULL);
+
+        bResult = (context->m_hFile != INVALID_HANDLE_VALUE);
+		if (!bResult)
+			context->HandleError(static_cast<LPCTSTR>(streams[i].m_strName));
+
+        if (bResult) {
+            try {
+                // set display name
+                eraserSafeAssign(context, context->m_strData, streams[i].m_strName);
+
+                // data stream size
+                if (streams[i].m_bDefault) {
+                    // we don't have the size for the default stream, get it
+                    context->m_uiFileSize.LowPart =
+                        GetFileSize(context->m_hFile, &context->m_uiFileSize.HighPart);
+
+                    if (context->m_uiFileSize.LowPart == (E_UINT32)-1 &&
+                        GetLastError() != NO_ERROR) {
+                        // GetFileSize failed
+                        bResult = false;
+                    }
+                } else {
+                    context->m_uiFileSize.QuadPart = streams[i].m_uSize;
+                }
+
+                if (bResult) {
+                    if (context->m_uiFileSize.QuadPart > 0) {
+                        // mmm, entropy.
+                        randomAddEntropy((E_PUINT8)&context->m_uiFileSize, sizeof(ULARGE_INTEGER));
+
+                        // we will also wipe the slack space at the end of the last cluster or if
+                        // cluster size isn't available, writes must at least be sector aligned
+                        E_UINT64 uTotal = fileSizeToArea(context, context->m_uiFileSize.QuadPart);
+
+                        context->m_uClusterSpace = (E_UINT32)(uTotal - context->m_uiFileSize.QuadPart);
+                        context->m_uiFileSize.QuadPart = uTotal;
+
+                        // set progress info
+                        eraserProgressStartEstimate(context, context->m_uiFileSize.QuadPart);
+
+                        // and overwrite
+                        bResult = context->m_lpmMethod->m_pwfFunction(context);
+
+                        if (bResult) {
+                            // set stream length to zero so allocated clusters cannot be trailed
+                            lHigh = 0L;
+                            SetFilePointer(context->m_hFile, 0, &lHigh, FILE_BEGIN);
+                            SetEndOfFile(context->m_hFile);
+
+                            resetDate(context->m_hFile);
+                        }
+                    } else {
+                        // nothing to erase
+                        resetDate(context->m_hFile);
+                    }
+                }
+
+                CloseHandle(context->m_hFile);
+
+            } catch (CException *e) {
+                handleException(e, context);
+
+                bResult = false;
+                SetLastError(ERROR_GEN_FAILURE);
+                CloseHandle(context->m_hFile);
+            }
+        }
+
+        if (!bResult) {
+            // if we were terminated while erasing a stream, the stream
+            // that wasn't completed will be added to the error list
+            CString strError;
+            formatError(strError);
+
+            if (!strError.IsEmpty()) {
+                strError = " (" + strError + ")";
+            }
+            strError = streams[i].m_strName + strError;
+            context->m_saFailed.Add(strError);
+
+            if (iSize > 1) {
+                eraserAddError1(context, IDS_ERROR_ADS, streams[i].m_strName);
+            }
+
+            break;
+        }
+    }
+
+    return bResult;
+}
+
+bool
+wipeFile(CEraserContext *context)
+{
+    try {
+        E_UINT32 uAttributes;
+        DataStreamArray streams;
+        DataStream defaultStream;
+
+        // default stream
+        defaultStream.m_strName = context->m_strData;
+        defaultStream.m_bDefault = true;
+
+        // get file attributes
+        uAttributes = GetFileAttributes(defaultStream.m_strName);
+
+        // if the file does not exist or an error has occurred
+        if (uAttributes == (E_UINT32)-1) {
+            CString strError;
+            formatError(strError);
+
+            if (!strError.IsEmpty()) {
+                strError = " (" + strError + ")";
+            }
+            strError = defaultStream.m_strName + strError;
+            context->m_saFailed.Add(strError);
+            return false;
+        }
+
+        // ignore read-only
+        SetFileAttributes(defaultStream.m_strName, FILE_ATTRIBUTE_NORMAL);
+
+        if (isWindowsNT &&
+            (bitSet(uAttributes, FILE_ATTRIBUTE_COMPRESSED) ||
+             bitSet(uAttributes, FILE_ATTRIBUTE_ENCRYPTED)  ||
+             bitSet(uAttributes, FILE_ATTRIBUTE_SPARSE_FILE))) {
+            // requires special processing
+            E_UINT32 uResult = wipeCompressedFile(context);
+
+            if (uResult == WCF_FAILURE) {
+                context->m_saFailed.Add(defaultStream.m_strName);
+                return false;
+            } else if (uResult == WCF_NOACCESS) {
+                CString strError;
+                strError.Format("%s (Administrator privileges required)", defaultStream.m_strName);
+
+                context->m_saFailed.Add(strError);
+                return false;
+            } else if (uResult == WCF_SUCCESS) {
+                return true;
+            }
+
+            // if file was not really compressed, erase normally
+        }
+
+        // search for alternate data streams (NTFS only)
+        if (isWindowsNT && bitSet(context->m_lsSettings.m_uItems, fileAlternateStreams)) {
+            findAlternateDataStreams(context, defaultStream.m_strName, streams);
+        }
+
+		// add the default (unnamed) data stream
+        streams.Add(defaultStream);
+
+        if (wipeDataStreams(context, streams)) {
+            return eraserOK(eraserRemoveFile((LPVOID)(LPCTSTR)defaultStream.m_strName,
+                                             (E_UINT16)defaultStream.m_strName.GetLength()));
+        }
+    } catch (CException *e) {
+        handleException(e, context);
+    }
+
+    return false;
+}
Index: /trunk/EraserDll/Custom.h
===================================================================
--- /trunk/EraserDll/Custom.h	(revision 4)
+++ /trunk/EraserDll/Custom.h	(revision 4)
@@ -0,0 +1,27 @@
+// Custom.h
+//
+// Eraser. Secure data removal. For Windows.
+// Copyright © 1997-2001  Sami Tolvanen (sami@tolvanen.com).
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#ifndef CUSTOM_H
+#define CUSTOM_H
+
+bool
+wipeFileWithCustom(CEraserContext *context);
+
+#endif // CUSTOM_H
Index: /trunk/EraserDll/EraserDllInternal.h
===================================================================
--- /trunk/EraserDll/EraserDllInternal.h	(revision 4)
+++ /trunk/EraserDll/EraserDllInternal.h	(revision 4)
@@ -0,0 +1,835 @@
+// EraserDllInternal.h
+// Internal header file for the Eraser Library
+//
+// Eraser. Secure data removal. For Windows.
+// Copyright © 1997-2001  Sami Tolvanen (sami@tolvanen.com).
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#ifndef ERASER_INTERNAL_H
+#define ERASER_INTERNAL_H
+
+#define USE_TRACE_OUTPUT
+#define USE_TRACE_BASE
+
+
+// debugging
+//
+#ifdef _DEBUG
+    #ifndef USE_TRACE_OUTPUT
+        #undef TRACE0
+        #define TRACE0(x)
+    #endif
+#endif
+
+#ifdef USE_TRACE_LOCK
+    #define eraserTraceLock(x) TRACE0(x)
+#else
+    #define eraserTraceLock(x)
+#endif
+#ifdef USE_TRACE_QUERY
+    #define eraserTraceQuery(x) TRACE0(x)
+#else
+    #define eraserTraceQuery(x)
+#endif
+#ifdef USE_TRACE_PROGRESS
+    #define eraserTraceProgress(x) TRACE0(x)
+#else
+    #define eraserTraceProgress(x)
+#endif
+#ifdef USE_TRACE_BASE
+    #define eraserTraceBase(x) TRACE0(x)
+#else
+    #define eraserTraceBase(x)
+#endif
+
+// constants
+//
+// buffer size for disk operations (divisible by 3, 4, 512 and 4096)
+const E_UINT32 ERASER_DISK_BUFFER_SIZE
+     = 10567680; // Added extra zero 09-04-2007
+// maximum file size for overwriting the free disk space
+const E_UINT32 ERASER_MAX_FILESIZE
+    = 422707200; // Added extra 2 zero 09-04-2007
+
+// how many times files renamed on NT
+const E_UINT16 ERASER_FILENAME_PASSES
+    = 7;
+// how many times directory entry cleaning can be restarted on 9x
+const E_UINT32 ERASER_MAXIMUM_RESTARTS
+    = 10;
+
+// sector size
+const E_UINT16 DEFAULT_SECTOR_SIZE
+    = 512;
+
+
+// literal constants
+//
+// temporary folders
+const LPCTSTR ERASER_TEMP_DIRECTORY
+    = "~ERAFSWD.TMP";
+const LPCTSTR ERASER_TEMP_DIRECTORY_NTFS_ENTRIES
+    = "~ERAFEWD.";
+// module names
+const LPCTSTR ERASER_MODULENAME_KERNEL
+    = "KERNEL32.DLL";
+const LPCTSTR ERASER_MODULENAME_NTDLL
+    = "NTDLL.DLL";
+const LPCTSTR ERASER_MODULENAME_SFC
+    = "SFC.DLL";
+// function names
+const LPCTSTR ERASER_FUNCTIONNAME_GETDISKFREESPACEEX
+    = "GetDiskFreeSpaceExA";
+const LPCTSTR ERASER_FUNCTIONNAME_NTFSCONTROLFILE
+    = "NtFsControlFile";
+const LPCTSTR ERASER_FUNCTIONNAME_NTQUERYINFORMATIONFILE
+    = "NtQueryInformationFile";
+const LPCTSTR ERASER_FUNCTIONNAME_RTLNTSTATUSTODOSERROR
+    = "RtlNtStatusToDosError";
+const LPCTSTR ERASER_FUNCTIONNAME_SFCISFILEPROTECTED
+    = "SfcIsFileProtected";
+// progress messages
+const LPCTSTR ERASER_MESSAGE_WORK
+    = "Overwriting...";
+const LPCTSTR ERASER_MESSAGE_SEARCH
+    = "Searching...";
+const LPCTSTR ERASER_MESSAGE_CLUSTER
+    = "Cluster Tips...";
+const LPCTSTR ERASER_MESSAGE_FILENAMES
+    = "File Names...";
+const LPCTSTR ERASER_MESSAGE_FILENAMES_RETRY
+    = "File Names... Retrying %u";
+const LPCTSTR ERASER_MESSAGE_DIRENTRY
+    = "Directory Entries...";
+const LPCTSTR ERASER_MESSAGE_DIRENTRY_RETRY
+    = "Directory Entries... Retrying %u";
+const LPCTSTR ERASER_MESSAGE_MFT
+    = "Master File Table Records...";
+const LPCTSTR ERASER_MESSAGE_MFT_WAIT
+    = "Master File Table Records... File %u";
+const LPCTSTR ERASER_MESSAGE_REMOVING
+    = "Removing Temporary Files...";
+
+
+// function type definitions
+//
+typedef BOOL (WINAPI *SFCISFILEPROTECTED)(HANDLE, LPCWSTR);
+typedef BOOL (WINAPI *GETDISKFREESPACEEX)(LPCTSTR, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER);
+
+class CEraserContext;
+typedef bool (*WIPEFUNCTION)(CEraserContext*);
+
+
+// converts boolean to ERASER_RESULT
+//
+#define truthToResult(x)    ((x) ? ERASER_OK : ERASER_ERROR);
+
+
+// settings
+//
+#include "Pass.h"
+
+#pragma pack(1)
+
+struct LibrarySettings
+{
+    LibrarySettings() {
+        ZeroMemory(this, sizeof(LibrarySettings));
+    }
+
+    ~LibrarySettings() {
+        if (m_lpCMethods) {
+            delete[] m_lpCMethods;
+            m_lpCMethods = 0;
+        }
+
+        ZeroMemory(this, sizeof(LibrarySettings));
+    }
+
+    LibrarySettings& operator=(LibrarySettings& rs) {
+        if (this != &rs) {
+            m_nFileMethodID     = rs.m_nFileMethodID;
+            m_nUDSMethodID      = rs.m_nUDSMethodID;
+            m_uItems            = rs.m_uItems;
+
+            m_nFileRandom       = rs.m_nFileRandom;
+            m_nUDSRandom        = rs.m_nUDSRandom;
+
+            if (m_lpCMethods) {
+                if (m_nCMethods > 0) {
+                    ZeroMemory(m_lpCMethods, m_nCMethods * sizeof(METHOD));
+                }
+                delete[] m_lpCMethods;
+                m_lpCMethods = 0;
+            }
+
+            m_nCMethods = rs.m_nCMethods;
+            m_lpCMethods = new METHOD[rs.m_nCMethods];
+
+            for (BYTE i = 0; i < rs.m_nCMethods; i++) {
+                m_lpCMethods[i] = rs.m_lpCMethods[i];
+            }
+        }
+
+        return *this;
+    }
+
+    // files
+    E_UINT8     m_nFileMethodID;
+
+    // unused disk space
+    E_UINT8     m_nUDSMethodID;
+
+    // what to erase
+    E_UINT8     m_uItems;
+
+    // built-in methods (req. settings)
+    E_UINT16    m_nFileRandom;
+    E_UINT16    m_nUDSRandom;
+
+    // custom methods
+    E_UINT8     m_nCMethods;
+    LPMETHOD    m_lpCMethods;
+};
+
+#pragma pack()
+
+// partition information
+//
+enum {
+    fsUnknown,
+    fsFAT,
+    fsFAT12,
+    fsFAT16,
+    fsFAT32,
+    fsNTFS
+};
+
+#define isFileSystemFAT(pi) \
+    ((pi.m_fsType == fsFAT)   || (pi.m_fsType == fsFAT12) || \
+     (pi.m_fsType == fsFAT16) || (pi.m_fsType == fsFAT32))
+
+#define isFileSystemNTFS(pi) \
+    (pi.m_fsType == fsNTFS)
+
+typedef class _PartitionInfo {
+public:
+    _PartitionInfo() {
+        clear();
+    }
+
+    ~_PartitionInfo() {
+        clear();
+    }
+
+    TCHAR    m_szDrive[4];
+    E_UINT8  m_fsType;
+    E_UINT32 m_uCluster;
+    E_UINT32 m_uSector;
+    bool     m_bLastSuccess;
+
+private:
+    void clear() {
+        strncpy(m_szDrive, " :\\", 4);
+        m_fsType = fsUnknown;
+        m_uCluster = 0;
+        m_uSector = DEFAULT_SECTOR_SIZE;
+        m_bLastSuccess = false;
+    }
+
+} PARTITIONINFO;
+
+
+// progress control
+//
+enum {
+    // display flags take the first 8 bits
+    progressCustom  = (1 << 8)      // use custom handling of progress
+};
+
+
+// the eraser context
+//
+
+
+class CEraserContext
+{
+public:
+	
+    CEraserContext() :
+    m_evStart(FALSE, FALSE),        // non-signaled, automatic
+    m_evDone(TRUE, TRUE),           // signaled, manual
+    m_evKillThread(FALSE, TRUE),    // non-signaled, manual
+    m_evThreadKilled(TRUE, TRUE),   // signaled, manual
+    m_evTestContinue(FALSE, TRUE), m_dwFinishAction(0) { // non-signaled, manual
+        clear();
+    }
+
+    ~CEraserContext() {
+        if (AfxIsValidAddress(m_pwtThread, sizeof(CWinThread))) {
+            ::TerminateThread(m_pwtThread->m_hThread, 1);
+            ASSERT(0);
+        }
+        clear();
+    }
+
+    // use synchronization when accessing while thread: killed (running)
+    //   r = can be assigned from the calling process, LOCK BEFORE READING
+    //   w = can be read from calling process, LOCK BEFORE WRITING
+    //   - = no need to lock for reading or writing
+
+    // Control
+    CWinThread          *m_pwtThread;                       // Pointer to the thread that handles erasing
+    CCriticalSection    m_csLock;                           // For synchronizing access to context variables
+    CEvent              m_evStart;                          // Signaled if OK to start running the thread
+    CEvent              m_evDone;                           // Signaled if operation completed
+    CEvent              m_evKillThread;                     // Signaled when thread must stop
+    CEvent              m_evThreadKilled;                   // Signaled when thread not running
+    // context identification
+    E_UINT32            m_uOwnerThreadID;                   // ID of the calling thread
+    E_UINT16            m_uContextID;                       // Random ID
+    // Data type
+    ERASER_DATA_TYPE    m_edtDataType;          // rw (-w)  // Data type of items on the list
+    // Data
+    CString             m_strData;              // -- (-w)  // Current item being processed
+    CStringArray        m_saData;               // rw (--)  // List of items to process
+    // Internal data
+    CStringList         *m_pstrlDirectories;                // Pointer to a list of directories to process when clearing file names
+    // I/O
+    // Buffer
+    E_PUINT32           m_puBuffer;                         // Pointer to write buffer
+    // File
+    HANDLE              m_hFile;                            // Handle to the file being overwritten
+    ULARGE_INTEGER		m_uiFileSize;                       // Size of the area to overwrite from the file
+    ULARGE_INTEGER      m_uiFileStart;                      // File position where overwriting begins
+    E_UINT32            m_uClusterSpace;                    // Size of the cluster tip area for the current item
+    // Partition info
+    PARTITIONINFO       m_piCurrent;                        // Information about the current partition
+    // Overwriting method
+    LPMETHOD            m_lpmMethod;                        // Pointer to the currently used overwriting method
+    METHOD              m_mThreadLocalMethod;               // Possible local copy of a built-in method (if valid, m_lpmMethod points to this)
+    // Notification
+    HWND                m_hwndWindow;           // rw (rw)  // Recipient of notification messages
+    E_UINT32            m_uWindowMessage;       // rw (rw)  // Window message to send
+    // Statistics
+    E_UINT64            m_uStatErasedArea;      // -w (--)  // Size of erased area
+    E_UINT64            m_uStatTips;            // -w (--)  // Size of cluster tip area
+    E_UINT64            m_uStatWiped;           // -w (--)  // Amount of data written
+    E_UINT32            m_uStatTime;            // -w (--)  // Write time
+    // Results
+    CStringArray        m_saFailed;             // -w (--)  // List of failed items
+    CStringArray        m_saError;              // -w (--)  // List of error messages
+    // Progress
+    E_UINT32            m_uProgressTimeLeft;    // -- (-w)  // Estimated time until current item is processed
+    E_UINT16            m_uProgressCurrentPass; // -- (-w)  // Overwriting pass that is being written
+    E_UINT16            m_uProgressPasses;      // -- (-w)  // Number of overwriting passes used
+    E_UINT8             m_uProgressPercent;     // -- (-w)  // Progress for current item
+    E_UINT8             m_uProgressTotalPercent;// -- (-w)  // Total progress
+    CString             m_strProgressMessage;   // -- (-w)  // Message to show, updated on ERASER_WIPE_{BEGIN,UPDATE}
+    // Internal progress
+    E_UINT64            m_uProgressSize;                    // Size of the area being overwritten (for the current item)
+    E_UINT64            m_uProgressWiped;                   // Amount of data written so far (for the current item)
+    E_UINT32            m_uProgressFiles;                   // Number of files to process 
+    E_UINT32            m_uProgressWipedFiles;              // Number of files processed
+    E_UINT32            m_uProgressFolders;                 // Number of directories processed (when clearing directory entries)
+    E_UINT32            m_uProgressDrives;                  // Number of drives to process
+    E_UINT32            m_uProgressWipedDrives;             // Number of drives processed
+    E_UINT8             m_uProgressTaskPercent;             // Total progress percentage based on the portion of the work completed
+    E_UINT8             m_uProgressTasks;                   // For keeping track of total progress
+    E_UINT32            m_uProgressStartTime;               // For estimating time left
+    // Display and progress control
+    E_UINT16            m_uProgressFlags;       // -- (-w)  // See above for flag descriptions, display flags in EraserDll.h
+    // Settings
+    LibrarySettings     m_lsSettings;                       // Context-specific settings
+    // Test mode
+    E_UINT8             m_uTestMode;            // rw (--)  // Not 0 = files opened with sharing and operation paused after each pass
+    CEvent              m_evTestContinue;                   // Signal to continue after pause
+	DWORD				m_dwFinishAction;					//finish action: shutdown system, reboot, none
+	EraserErrorHandler  m_pfnErrorHandler;					// Error handler callback function. Called when "CreateFile" error is detected;
+	void*				m_pErrorHandlerParam;				// Additional parameter for error handler callback
+
+	inline DWORD HandleError(LPCTSTR szFileName, DWORD dwErrorCode = GetLastError())
+	{
+		if(!m_pfnErrorHandler)
+			return 0;
+		return m_pfnErrorHandler(szFileName, dwErrorCode, this, m_pErrorHandlerParam);
+	}
+private:
+    void clear() {
+        m_pwtThread = 0;
+        m_evStart.ResetEvent();
+        m_evDone.SetEvent();
+        m_evKillThread.ResetEvent();
+        m_evThreadKilled.SetEvent();
+        m_uOwnerThreadID = 0;
+        m_uContextID = 0;
+        m_edtDataType = ERASER_DATA_FILES;
+        m_strData.Empty();
+        m_saData.RemoveAll();
+        m_pstrlDirectories = 0;
+        m_puBuffer = 0;
+        m_hFile = INVALID_HANDLE_VALUE;
+        m_uiFileSize.QuadPart = 0;
+        m_uiFileStart.QuadPart = 0;
+        m_uClusterSpace = 0;
+        m_hwndWindow = NULL;
+        m_uWindowMessage = WM_NULL;
+        m_uStatErasedArea = 0;
+        m_uStatTips = 0;
+        m_uStatWiped = 0;
+        m_uStatTime = 0;
+        m_saFailed.RemoveAll();
+        m_saError.RemoveAll();
+        m_uProgressTimeLeft = 0;
+        m_uProgressCurrentPass = 0;
+        m_uProgressPasses = 0;
+        m_uProgressPercent = 0;
+        m_uProgressTotalPercent = 0;
+        m_strProgressMessage.Empty();
+        m_uProgressSize = 0;
+        m_uProgressWiped = 0;
+        m_uProgressFiles = 0;
+        m_uProgressWipedFiles = 0;
+        m_uProgressDrives = 0;
+        m_uProgressWipedDrives = 0;
+        m_uProgressTaskPercent = 0;
+        m_uProgressTasks = 0;
+        m_uProgressFolders = 0;
+        m_uProgressStartTime = 0;
+        m_uProgressFlags = 0;
+        m_lpmMethod = 0;
+        m_uTestMode = 0;
+        m_evTestContinue.ResetEvent();
+		m_pfnErrorHandler = NULL;
+		m_pErrorHandlerParam = NULL;
+    }
+
+
+    // no copying, pass a pointer instead
+    CEraserContext(const CEraserContext&);
+    CEraserContext& operator=(const CEraserContext&);
+};
+
+
+// context range (ERASER_MAX_CONTEXT - ERASER_MIN_CONTEXT + 1)
+//
+#define ERASER_MIN_CONTEXT              0   // this one should probably be left alone
+#define ERASER_MAX_CONTEXT              127 // max. 65534 to make sure ERASER_INVALID_CONTEXT is unique
+
+// context helpers
+#define eraserContextID(x)              ((E_UINT16)HIWORD((E_UINT32)(x)))
+#define eraserContextIndex(x)           ((E_UINT16)LOWORD((E_UINT32)(x)))
+
+#define eraserSetContextID(x, id)       ((x) = (ERASER_HANDLE)MAKELONG(eraserContextIndex(x), (E_UINT16)(id)))
+#define eraserSetContextIndex(x, index) ((x) = (ERASER_HANDLE)MAKELONG((E_UINT16)(index), eraserContextID(x)))
+
+// validity of the context index
+#define eraserContextOK(x)              (( eraserContextIndex(x) >= ERASER_MIN_CONTEXT ) && \
+                                         ( eraserContextIndex(x) <= ERASER_MAX_CONTEXT ))
+
+
+// access control
+#define eraserContextAccessName(x, name) \
+    eraserTraceLock("eraserContextAccess\n"); \
+    CSingleLock name(&(x)->m_csLock, TRUE)
+#define eraserContextAccess(x) \
+    eraserContextAccessName(x, slc)
+#define eraserContextReleaseName(name) \
+    do { \
+        eraserTraceLock("eraserContextRelease\n"); \
+        (name).Unlock(); \
+    } while (0)
+#define eraserContextRelease() \
+    eraserContextReleaseName(slc)
+#define eraserContextRelockName(name) \
+    do { \
+        eraserTraceLock("eraserContextRelock\n"); \
+        (name).Lock(); \
+    } while (0)
+#define eraserContextRelock() \
+    eraserContextRelockName(slc)
+#define eraserContextLock(x) \
+    do { \
+        eraserTraceLock("eraserContextLock\n"); \
+        (x)->m_csLock.Lock(); \
+    } while (0)
+#define eraserContextUnlock(x) \
+    do { \
+        eraserTraceLock("eraserContextUnlock\n"); \
+        (x)->m_csLock.Unlock(); \
+    } while (0)
+#define eraserSafeAssign(x, y, z) \
+    do { \
+        eraserTraceLock("eraserSafeAssign\n"); \
+        eraserContextLock(x); \
+        (y) = (z); \
+        eraserContextUnlock(x); \
+    } while (0)
+
+
+// status
+#define eraserInternalCompleted(x) \
+    (WaitForSingleObject((x)->m_evDone, 0) == WAIT_OBJECT_0)
+#define eraserInternalFailed(x) \
+    (!eraserInternalCompleted(x))
+#define eraserInternalTerminated(x) \
+    (WaitForSingleObject((x)->m_evKillThread, 0) == WAIT_OBJECT_0)
+#define eraserInternalIsRunning(x) \
+    (WaitForSingleObject((x)->m_evThreadKilled, 0) != WAIT_OBJECT_0)
+
+// error - call only from running thread
+inline void
+eraserAddError(CEraserContext *context, E_UINT32 rid)
+{
+    eraserTraceBase("eraserAddError\n");
+    CString strError;
+    try {
+        if (strError.LoadString(rid)) {
+            context->m_saError.Add(strError);
+        }
+    } catch (...) {
+        ASSERT(0);
+    }
+}
+
+inline void
+eraserAddError1(CEraserContext *context, E_UINT32 rid, LPCTSTR str)
+{
+    eraserTraceBase("eraserAddError\n");
+    CString strError;
+    try {
+        AfxFormatString1(strError, rid, str);
+        context->m_saError.Add(strError);
+    } catch (...) {
+        ASSERT(0);
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// definitions
+
+// for notifying UI window
+#define eraserBeginNotifyNoAccess(x) \
+    if ((x)->m_hwndWindow != NULL) { \
+        PostMessage((x)->m_hwndWindow, (x)->m_uWindowMessage, ERASER_WIPE_BEGIN, 0); \
+    }
+#define eraserBeginNotify(x) \
+    do { \
+        eraserTraceProgress("eraserBeginNotify\n"); \
+        eraserContextLock(x); \
+        eraserBeginNotifyNoAccess(x); \
+        eraserContextUnlock(x); \
+    } while (0)
+
+#define eraserUpdateNotifyNoAccess(x) \
+    if ((x)->m_hwndWindow != NULL) { \
+        PostMessage((x)->m_hwndWindow, (x)->m_uWindowMessage, ERASER_WIPE_UPDATE, 0); \
+    }
+#define eraserUpdateNotify(x) \
+    do { \
+        eraserTraceProgress("eraserUpdateNotify\n"); \
+        eraserContextLock(x); \
+        eraserUpdateNotifyNoAccess(x); \
+        eraserContextUnlock(x); \
+    } while (0)
+
+#define eraserTestPausedNotifyNoAccess(x) \
+    if ((x)->m_hwndWindow != NULL) { \
+        PostMessage((x)->m_hwndWindow, (x)->m_uWindowMessage, ERASER_TEST_PAUSED, 0); \
+    }
+#define eraserTestPausedNotify(x) \
+    do { \
+        eraserTraceProgress("eraserTestPausedNotify\n"); \
+        eraserContextLock(x); \
+        eraserTestPausedNotifyNoAccess(x); \
+        eraserContextUnlock(x); \
+    } while (0)
+
+#define eraserEndThread(x, return_value) \
+    do { \
+        eraserTraceBase("eraserEndThread\n"); \
+        eraserContextLock(x); \
+        (x)->m_evThreadKilled.SetEvent(); \
+        if ((x)->m_hwndWindow != NULL) { \
+            PostMessage((x)->m_hwndWindow, (x)->m_uWindowMessage, \
+                        ERASER_WIPE_DONE, 0); \
+        } \
+        (x)->m_pwtThread = 0; \
+        eraserContextUnlock(x); \
+        return (return_value); \
+    } while (0)
+
+// for controlling what UI shows
+#define eraserProgressSetMessage(x, message) \
+    do { \
+        eraserTraceProgress("eraserProgressSetMessage\n"); \
+        eraserContextLock(x); \
+        (x)->m_strProgressMessage = message; \
+        eraserContextUnlock(x); \
+    } while (0)
+
+#define eraserProgressStartEstimate(x, size) \
+    do { \
+        eraserTraceProgress("eraserProgressStartEstimate\n"); \
+        (x)->m_uProgressWiped = 0; \
+        (x)->m_uProgressSize = (size); \
+        (x)->m_uProgressStartTime = GetTickCount(); \
+    } while (0)
+
+// default configuration
+#define eraserDispDefault(x) \
+    do { \
+        eraserTraceProgress("eraserDispDefault\n"); \
+        eraserContextLock(x); \
+        (x)->m_uProgressFlags = eraserDispPass | eraserDispTime | eraserDispInit; \
+        (x)->m_strProgressMessage = ERASER_MESSAGE_WORK; \
+        eraserContextUnlock(x); \
+    } while (0)
+
+// counting files (not overwriting)
+#define eraserDispSearch(x) \
+    do { \
+        eraserTraceProgress("eraserDispSearch\n"); \
+        eraserContextLock(x); \
+        (x)->m_uProgressFlags = 0; \
+        (x)->m_strProgressMessage = ERASER_MESSAGE_SEARCH; \
+        eraserContextUnlock(x); \
+    } while (0)
+
+// erasing cluster tips
+#define eraserDispClusterTips(x) \
+    do { \
+        eraserTraceProgress("eraserDispClusterTips\n"); \
+        eraserContextLock(x); \
+        (x)->m_uProgressFlags = progressCustom; \
+        (x)->m_strProgressMessage = ERASER_MESSAGE_CLUSTER; \
+        eraserContextUnlock(x); \
+    } while (0)
+
+// erasing file names
+#define eraserDispFileNames(x) \
+    do { \
+        eraserTraceProgress("eraserDispFileNames\n"); \
+        eraserContextLock(x); \
+        (x)->m_uProgressFlags = eraserDispInit | progressCustom; \
+        (x)->m_strProgressMessage = ERASER_MESSAGE_FILENAMES; \
+        eraserContextUnlock(x); \
+    } while (0)
+
+// erasing directory entries
+#define eraserDispDirEntries(x) \
+    do { \
+        eraserTraceProgress("eraserDispDirEntries\n"); \
+        eraserContextLock(x); \
+        (x)->m_uProgressFlags = eraserDispInit | progressCustom; \
+        (x)->m_strProgressMessage = ERASER_MESSAGE_DIRENTRY; \
+        eraserContextUnlock(x); \
+    } while (0)
+
+// erasing MFT records
+#define eraserDispMFT(x) \
+    do { \
+        eraserTraceProgress("eraserDispMFT\n"); \
+        eraserContextLock(x); \
+        (x)->m_uProgressFlags = eraserDispInit | progressCustom; \
+        (x)->m_strProgressMessage = ERASER_MESSAGE_MFT; \
+        eraserContextUnlock(x); \
+    } while (0)
+
+
+// handling exceptions
+#define handleException(e, context) \
+    do { \
+        ASSERT(0); \
+        try { \
+            ZeroMemory(szExceptionBuffer, uExceptionBufferSize * sizeof(TCHAR)); \
+            (e)->GetErrorMessage(szExceptionBuffer, uExceptionBufferSize); \
+            context->m_saError.Add((LPCTSTR)szExceptionBuffer); \
+        } catch (...) {\
+        } \
+        try { \
+            (e)->Delete(); \
+        } catch (...) { \
+        } \
+    } while (0)
+
+
+///////////////////////////////////////////////////////////////////////////////
+// helper functions
+
+#define eraserBool(x, y) \
+    if (!(y)) { (x) = false; }
+
+// round up to nearest multiple
+//
+#define roundUp(x, multiple) \
+    (((x) + ((multiple) - 1)) & ~((multiple) - 1))
+
+// string conversion
+//
+inline void
+asciiToUnicode(LPCSTR ansi_string, LPWSTR unicode_string)
+{
+    if (ansi_string == NULL || unicode_string == NULL) {
+        return;
+    }
+
+    if (ansi_string == (LPCSTR) unicode_string) {
+        ASSERT(0);
+        return;
+    }
+
+    try {
+        E_INT32 loop_index = 0;
+
+        while (ansi_string[loop_index] != 0x00) {
+            unicode_string[loop_index] = ansi_string[loop_index];
+            loop_index++;
+        }
+
+        unicode_string[loop_index] = 0;
+    } catch (...) {
+        ASSERT(0);
+    }
+}
+
+inline void
+unicodeToCString(LPCWSTR source_string, CString& destination_string)
+{
+    destination_string.Empty();
+
+    if (source_string == NULL) {
+        ASSERT(0);
+        return;
+    }
+
+    try {
+        int index = 0;
+        TCHAR character_to_add = 0;
+
+        character_to_add = (TCHAR)source_string[index];
+
+        while (character_to_add != 0) {
+            destination_string += character_to_add;
+            index++;
+            character_to_add = (TCHAR)source_string[index];
+        }
+    } catch (...) {
+        ASSERT(0);
+    }
+}
+
+inline E_UINT64
+fileSizeToArea(CEraserContext *context, const E_UINT64& uFileSize)
+{
+    E_UINT64 uBlockSize = max(context->m_piCurrent.m_uCluster,
+        max(context->m_piCurrent.m_uSector, DEFAULT_SECTOR_SIZE));
+    return roundUp(uFileSize, uBlockSize);
+}
+
+inline void
+fillPassData(E_PUINT32 puBuffer, E_UINT32 uSize, LPPASS pPass)
+{
+    // fills buffer with data
+    try {
+        if (pPass->bytes == 1) {
+            if (pPass->byte1 != RND_DATA) {
+                FillMemory((LPVOID)puBuffer, uSize, (E_UINT8)pPass->byte1);
+            }
+        } else {
+            FillMemoryWith((LPVOID)puBuffer, uSize, pPass->bytes,
+                (E_UINT8)pPass->byte1, (E_UINT8)pPass->byte2, (E_UINT8)pPass->byte3);
+        }
+    } catch (...) {
+        ASSERT(0);
+    }
+}
+
+inline void
+shufflePassArray(PASS *pPassArray, E_UINT16 uSize)
+{
+    if (uSize < 2 || uSize > PASSES_MAX) {
+        return;
+    }
+
+    E_UINT16 uLast;
+    E_UINT16 uRandom;
+    E_PUINT32 puRandomArray = 0;
+    PASS pass;
+
+    // shuffles pass array of size uSize
+    try {
+        uLast = uSize;
+
+        // retrieve random bytes
+        puRandomArray = new E_UINT32[uSize - 1];
+
+        if (!randomFill((E_PUINT8)puRandomArray, (uSize - 1) * sizeof(E_UINT32))) {
+            // in the unlikely case that randomFill fails, use ISAAC
+            isaacFill((E_PUINT8)puRandomArray, (uSize - 1) * sizeof(E_UINT32));
+        }
+
+        // shuffle the array by swapping the last element with a
+        // random element and the repeating without the last element
+
+        while (uLast > 1) {
+            // uRandom = [0, uLast - 1]
+            uRandom = (E_UINT16)(puRandomArray[uLast - 2] % uLast);
+
+            if (--uLast > uRandom) {
+                pass                = pPassArray[uRandom];
+                pPassArray[uRandom] = pPassArray[uLast];
+                pPassArray[uLast]   = pass;
+            }
+        }
+
+        ZeroMemory(puRandomArray, uSize - 1);
+        delete[] puRandomArray;
+        puRandomArray = 0;
+
+    } catch (...) {
+        ASSERT(0);
+        try {
+            if (puRandomArray) {
+                ZeroMemory(puRandomArray, uSize - 1);
+                delete[] puRandomArray;
+                puRandomArray = 0;
+            }
+        } catch (...) {
+        }
+    }
+
+    setPassOne(pass, 0);
+    uRandom = 0;
+}
+
+inline void
+setBufferSize(CEraserContext *context, E_UINT32& uUsedBufferSize)
+{
+    // sets minimum required buffer size
+    try {
+        if (context->m_uiFileSize.QuadPart < (E_UINT64)ERASER_DISK_BUFFER_SIZE) {
+            uUsedBufferSize = context->m_uiFileSize.LowPart;
+            return;
+        }
+    } catch (...) {
+        ASSERT(0);
+    }
+    uUsedBufferSize = ERASER_DISK_BUFFER_SIZE;
+}
+
+#endif
