source: trunk/EraserDll/Eraser.cpp @ 40

Revision 40, 76.5 KB checked in by lowjoel, 7 years ago (diff)

-Enable visual styles for all projects
-Standardize the file header for the Verify project
-Remove all the Shared header files. I will create a Shared project which creates a static library to reduce compile times further

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
Line 
1// Eraser.cpp
2//
3// Eraser. Secure data removal. For Windows.
4// Copyright © 1997-2001  Sami Tolvanen (sami@tolvanen.com).
5// Copyright © 2007 The Eraser Project
6//
7// This program is free software; you can redistribute it and/or
8// modify it under the terms of the GNU General Public License
9// as published by the Free Software Foundation; either version 2
10// of the License, or (at your option) any later version.
11//
12// This program is distributed in the hope that it will be useful,
13// but WITHOUT ANY WARRANTY; without even the implied warranty of
14// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15// GNU General Public License for more details.
16//
17// You should have received a copy of the GNU General Public License
18// along with this program; if not, write to the Free Software
19// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20// 02111-1307, USA.
21
22#include "stdafx.h"
23#include "Eraser.h"
24#include "EraserDll.h"
25#include "Common.h"
26
27#include "Options.h"
28#include "OptionsDlg.h"
29#include "ReportDialog.h"
30
31#include "RND.h"
32#include "DOD.h"
33#include "Gutmann.h"
34#include "Custom.h"
35
36#include "File.h"
37#include "NTFS.h"
38#include "FreeSpace.h"
39#include "FAT.h"
40
41#include "..\EraserUI\VisualStyles.h"
42#include "..\shared\FileHelper.h"
43#include "..\shared\key.h"
44
45#ifdef _DEBUG
46#define new DEBUG_NEW
47#undef THIS_FILE
48static char THIS_FILE[] = __FILE__;
49#endif
50
51#undef MAX_PATH
52#define MAX_PATH 2048 //HACK: Some filenames under Vista can exceed the 260
53                      //char limit. This will have to do for now.
54
55/////////////////////////////////////////////////////////////////////////////
56// CEraserApp
57
58BEGIN_MESSAGE_MAP(CEraserApp, CWinApp)
59    //{{AFX_MSG_MAP(CEraserApp)
60        // NOTE - the ClassWizard will add and remove mapping macros here.
61        //    DO NOT EDIT what you see in these blocks of generated code!
62    //}}AFX_MSG_MAP
63END_MESSAGE_MAP()
64
65/////////////////////////////////////////////////////////////////////////////
66// CEraserApp construction
67
68CEraserApp::CEraserApp()
69{
70    _set_se_translator(SeTranslator);
71}
72
73BOOL CEraserApp::InitInstance()
74{
75    // determine the operating system
76    OSVERSIONINFO ov;
77    ZeroMemory(&ov, sizeof(OSVERSIONINFO));
78    ov.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
79    GetVersionEx(&ov);
80
81    //isWindowsNT = (ov.dwPlatformId == VER_PLATFORM_WIN32_NT);
82    //isWindowsNT =  (ov.dwPlatformId == VER_PLATFORM_WIN32_NT  && (ov.dwMajorVersion > 5 || (ov.dwMajorVersion == 5 && ov.dwMinorVersion >= 1)));
83    isWindowsNT = (ov.dwPlatformId == VER_PLATFORM_WIN32_NT  && (ov.dwMajorVersion >= 4));
84
85    // initialize the context array
86    eraserContextArrayAccess();
87    ZeroMemory(eraserContextArray, sizeof(CEraserContext*) * (ERASER_MAX_CONTEXT + 1));
88
89    // initialize reference counter
90    eraserLibraryUnlock();
91
92    return CWinApp::InitInstance();
93}
94
95int CEraserApp::ExitInstance()
96{
97    // clean up
98    eraserLibraryUnlock();
99    eraserEnd();
100
101    return CWinApp::ExitInstance();
102}
103
104
105/////////////////////////////////////////////////////////////////////////////
106// The one and only CEraserApp object
107
108CEraserApp theApp;
109
110/////////////////////////////////////////////////////////////////////////////
111// definitions
112
113UINT eraserThread(LPVOID);
114
115/////////////////////////////////////////////////////////////////////////////
116// misc. helpers
117
118static void mySleep(UINT second) 
119{ 
120    MSG  msg; 
121    while( PeekMessage( &msg, NULL/*(HWND)this*/, 0, 0, PM_REMOVE ) ) 
122    { 
123        GetMessage( &msg, NULL, 0, 0 ); 
124        TranslateMessage(&msg); 
125        DispatchMessage(&msg); 
126    } 
127    clock_t start, finish; 
128    double  duration; 
129    start = clock(); 
130    for(;;) 
131    { 
132        finish = clock(); 
133        duration = (double)(finish - start) / CLOCKS_PER_SEC; 
134        if(duration > second) 
135        break; 
136    } 
137} 
138
139static inline bool
140overwriteFileName(LPCTSTR szFile, LPTSTR szLastFileName)
141{
142    TCHAR szNewName[MAX_PATH];
143    PTCHAR pszLastSlash;
144    E_UINT32 i, j, index, length;
145
146    try {
147        strncpy(szLastFileName, szFile, MAX_PATH);
148        pszLastSlash = strrchr(szLastFileName, '\\');
149
150        if (pszLastSlash == NULL) {
151            return false;
152        }
153
154        index = (pszLastSlash - szLastFileName) / sizeof(TCHAR);
155
156        strncpy(szNewName, szLastFileName, MAX_PATH);
157        length = (E_UINT32)strlen(szLastFileName);
158
159        for (i = 0; i < ERASER_FILENAME_PASSES; i++) {
160            // replace each non-'.' character with a random letter
161            isaacFill((E_PUINT8)(szNewName + index + 1), (length - index - 1) * sizeof(TCHAR));
162
163            for (j = index + 1; j < length; j++) {
164                if (szLastFileName[j] != '.') {
165                    szNewName[j] = ERASER_SAFEARRAY[((E_UINT16)szNewName[j]) % ERASER_SAFEARRAY_SIZE];
166                } else {
167                    szNewName[j] = '.';
168                }
169            }
170
171            if (MoveFile(szLastFileName, szNewName)) {
172                strncpy(szLastFileName, szNewName, MAX_PATH);
173            } else
174            {
175                Sleep(50); // Allow for Anti-Virus applications to stop looking at the file
176                if (MoveFile(szLastFileName, szNewName)) {
177                strncpy(szLastFileName, szNewName, MAX_PATH);
178                }
179            }
180        }
181
182        return true;
183    }
184    catch (...) {
185        ASSERT(0);
186    }
187
188    ZeroMemory(szNewName, MAX_PATH * sizeof(TCHAR));
189
190    return false;
191}
192
193static inline bool
194isFolderEmpty(LPCTSTR szFolder)
195{
196    bool            bEmpty = true;
197    HANDLE          hFind;
198    WIN32_FIND_DATA wfdData;
199    CString         strFolder(szFolder);
200
201    // make sure that the folder name ends with a backslash
202    if (strFolder[strFolder.GetLength() - 1] != '\\') {
203        strFolder += "\\";
204    }
205
206    hFind = FindFirstFile((LPCTSTR)(strFolder + "*"), &wfdData);
207
208    if (hFind != INVALID_HANDLE_VALUE) {
209        do {
210            if (bitSet(wfdData.dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY) &&
211                ISNT_SUBFOLDER(wfdData.cFileName)) {
212                continue;
213            }
214
215            bEmpty = false;
216            break;
217        }
218        while (FindNextFile(hFind, &wfdData));
219
220        VERIFY(FindClose(hFind));
221    }
222    return bEmpty;
223}
224
225// removes all files and subfolders from the given folder, use with caution
226static inline bool
227emptyFolder(LPCTSTR szFolder)
228{
229    bool            bEmpty = true;
230    HANDLE          hFind;
231    WIN32_FIND_DATA wfdData;
232    CString         strFolder(szFolder);
233    CString         strFile;
234
235    // make sure that the folder name ends with a backslash
236    if (strFolder[strFolder.GetLength() - 1] != '\\') {
237        strFolder += "\\";
238    }
239
240    hFind = FindFirstFile((LPCTSTR)(strFolder + "*"), &wfdData);
241
242    if (hFind != INVALID_HANDLE_VALUE) {
243        do {
244            strFile = strFolder + wfdData.cFileName;
245
246            if (bitSet(wfdData.dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY)) {
247                if (IS_SUBFOLDER(wfdData.cFileName)) {
248                    if (eraserError(eraserRemoveFolder((LPVOID)(LPCTSTR)strFile,
249                            (E_UINT16)strFile.GetLength(), ERASER_REMOVE_RECURSIVELY))) {
250                        bEmpty = false;
251                    }
252                }
253            } else {
254                if (eraserError(eraserRemoveFile((LPVOID)(LPCTSTR)strFile,
255                        (E_UINT16)strFile.GetLength()))) {
256                    bEmpty = false;
257                }
258            }
259        }
260        while (FindNextFile(hFind, &wfdData));
261
262        VERIFY(FindClose(hFind));
263    } else {
264        return false;
265    }
266    return bEmpty;
267}
268
269/////////////////////////////////////////////////////////////////////////////
270// context helpers
271
272static inline ERASER_RESULT
273contextToAddress(E_IN ERASER_HANDLE param1, E_OUT CEraserContext **pointer)
274{
275    // if you don't count all the error checking, this is quite fast, O(1)
276    if (!eraserContextOK(param1)) {
277        return ERASER_ERROR_PARAM1;
278    } else if (!AfxIsValidAddress(pointer, sizeof(CEraserContext*))) {
279        return ERASER_ERROR_PARAM2;
280    } else {
281        try {
282            E_UINT16 index = eraserContextIndex(param1);
283            eraserContextArrayAccess();
284            *pointer = eraserContextArray[index];
285            if (*pointer == 0) {
286                return ERASER_ERROR_PARAM1;
287            } else if (!AfxIsValidAddress(*pointer, sizeof(CEraserContext))) {
288                eraserContextArray[index] = 0;
289                *pointer = 0;
290                return ERASER_ERROR_PARAM1;
291            } else if ((*pointer)->m_uContextID != eraserContextID(param1) ||
292                       (*pointer)->m_uOwnerThreadID != ::GetCurrentThreadId()) {
293                // invalid context id or attempt to access from another thread
294                *pointer = 0;
295                return ERASER_ERROR_DENIED;
296            }
297        } catch (...) {
298            ASSERT(0);
299            return ERASER_ERROR_EXCEPTION;
300        }
301        return ERASER_OK;
302    }
303}
304
305/////////////////////////////////////////////////////////////////////////////
306// exported functions
307
308// Library initialization
309//
310ERASER_EXPORT
311eraserInit()
312{
313    AFX_MANAGE_STATE(AfxGetStaticModuleState());
314    eraserTraceBase("eraserInit\n");
315
316    try {
317        // increase the reference counter
318        eraserLibraryInit();
319        randomInit();
320
321        return ERASER_OK;
322    } catch (...) {
323        ASSERT(0);
324        return ERASER_ERROR_EXCEPTION;
325    }
326}
327
328ERASER_EXPORT
329eraserEnd()
330{
331    AFX_MANAGE_STATE(AfxGetStaticModuleState());
332    eraserTraceBase("eraserEnd\n");
333
334    ERASER_RESULT result = ERASER_OK;
335
336    // decrease the reference counter
337    eraserLibraryUninit();
338
339    eraserContextArrayAccess();
340
341    try {
342        // if nobody else is using this instance of the library, clean up
343        if (!eraserIsLibraryInit()) {
344            for (ERASER_HANDLE i = ERASER_MIN_CONTEXT; i <= ERASER_MAX_CONTEXT; i++) {
345                if (eraserContextArray[i] != 0) {
346                    if (AfxIsValidAddress(eraserContextArray[i], sizeof(CEraserContext))) {
347                        try {
348                            // this will stop unsynchronized access to the context
349                            VERIFY(eraserOK(eraserStop(i)));
350                            eraserContextLock(eraserContextArray[i]);
351                            delete eraserContextArray[i];
352                        } catch (...) {
353                            ASSERT(0);
354                            result = ERASER_ERROR_EXCEPTION;
355                        }
356                    }
357                    eraserContextArray[i] = 0;
358                }
359            }
360        }
361
362        // decrease prng reference counter
363        randomEnd();
364    } catch (...) {
365        ASSERT(0);
366        result = ERASER_ERROR_EXCEPTION;
367    }
368
369    return result;
370}
371
372
373// Context creation and destruction
374//
375ERASER_EXPORT
376eraserCreateContext(E_OUT ERASER_HANDLE *param1)
377{
378    AFX_MANAGE_STATE(AfxGetStaticModuleState());
379    eraserTraceBase("eraserCreateContext\n");
380
381    if (!eraserIsLibraryInit()) {
382        return ERASER_ERROR_INIT;
383    } else if (!AfxIsValidAddress(param1, sizeof(ERASER_HANDLE))) {
384        return ERASER_ERROR_PARAM1;
385    } else {
386        try {
387            *param1 = ERASER_INVALID_CONTEXT;
388        } catch (...) {
389            return ERASER_ERROR_PARAM1;
390        }
391    }
392
393    eraserContextArrayAccess();
394
395    // find first available context
396    for (E_UINT16 i = ERASER_MAX_CONTEXT; i >= ERASER_MIN_CONTEXT; i--) {
397        if (eraserContextArray[i] == 0) {
398            try {
399                eraserContextArray[i] = new CEraserContext();
400            } catch (...) {
401                eraserContextArray[i] = 0;
402                return ERASER_ERROR_MEMORY;
403            }
404
405            try {
406                if (!loadLibrarySettings(&eraserContextArray[i]->m_lsSettings)) {
407                    setLibraryDefaults(&eraserContextArray[i]->m_lsSettings);
408                }
409
410                // reseed the prng
411                isaacSeed();
412
413                // context identification
414                isaacFill((E_PUINT8)&eraserContextArray[i]->m_uContextID, sizeof(E_UINT16));
415                eraserContextArray[i]->m_uOwnerThreadID = ::GetCurrentThreadId();
416
417                // context handle is a combination of eraserContextArray
418                // index and the number of times this function is called
419                eraserSetContextID(*param1, eraserContextArray[i]->m_uContextID);
420                eraserSetContextIndex(*param1, i);
421            } catch (...) {
422                ASSERT(0);
423                if (AfxIsValidAddress(eraserContextArray[i], sizeof(CEraserContext))) {
424                    delete eraserContextArray[i];
425                    eraserContextArray[i] = 0;
426                }
427                return ERASER_ERROR_EXCEPTION;
428            }
429            return ERASER_OK;
430        }
431    }
432
433    return ERASER_ERROR_CONTEXT;
434}
435
436E_UINT8 convEraseMethod(ERASER_METHOD mIn)
437{
438    switch(mIn){
439        case ERASER_METHOD_LIBRARY:
440            return GUTMANN_METHOD_ID;
441            break;
442        case ERASER_METHOD_GUTMANN:
443            return GUTMANN_METHOD_ID;
444            break;
445        case ERASER_METHOD_DOD:
446            return DOD_METHOD_ID;
447            break;
448        case ERASER_METHOD_DOD_E:
449            return DOD_E_METHOD_ID;
450            break;
451        case ERASER_METHOD_PSEUDORANDOM:
452            return RANDOM_METHOD_ID;
453            break;
454        case ERASER_METHOD_FIRST_LAST_2KB:
455            return FL2KB_METHOD_ID;
456            break;
457        case ERASER_METHOD_SCHNEIER:
458            return SCHNEIER_METHOD_ID;
459            break;
460        default:
461            return mIn;
462    }
463}
464
465ERASER_EXPORT
466eraserCreateContextEx(E_OUT ERASER_HANDLE *param1, E_IN E_UINT8 param2, E_IN E_UINT16 param3, E_IN E_UINT8 param4)
467{
468    AFX_MANAGE_STATE(AfxGetStaticModuleState());
469    eraserTraceBase("eraserCreateContextEx\n");
470    LONG lRetStatus = ERASER_OK;
471    if (param2==0) {
472        return ERASER_ERROR_PARAM2;
473    } else if (param3 > PASSES_MAX || param3 < 1) {
474        return ERASER_ERROR_PARAM3;
475    }
476
477    // this one does all our basic sanity checks
478    ERASER_RESULT result = eraserCreateContext(param1);
479    if (eraserError(result)) {
480        return result;
481    } else {
482        try {
483            CEraserContext *context = 0;
484            if (eraserOK(contextToAddress(*param1, &context))) {
485                eraserContextAccess(context);
486                if (param4) {
487                    context->m_lsSettings.m_uItems = param4;
488                }
489                switch (param2) {
490                case GUTMANN_METHOD_ID:
491                    context->m_lsSettings.m_nFileMethodID = GUTMANN_METHOD_ID;
492                    context->m_lsSettings.m_nUDSMethodID  = GUTMANN_METHOD_ID;
493                    break;
494                case DOD_METHOD_ID:
495                    context->m_lsSettings.m_nFileMethodID = DOD_METHOD_ID;
496                    context->m_lsSettings.m_nUDSMethodID  = DOD_METHOD_ID;
497                    break;
498                case DOD_E_METHOD_ID:
499                    context->m_lsSettings.m_nFileMethodID = DOD_E_METHOD_ID;
500                    context->m_lsSettings.m_nUDSMethodID  = DOD_E_METHOD_ID;
501                    break;
502                case RANDOM_METHOD_ID:
503                    context->m_lsSettings.m_nFileMethodID = RANDOM_METHOD_ID;
504                    context->m_lsSettings.m_nUDSMethodID  = RANDOM_METHOD_ID;
505                    context->m_lsSettings.m_nFileRandom   = param3;
506                    context->m_lsSettings.m_nUDSRandom    = param3;
507                    break;
508                case FL2KB_METHOD_ID:
509                    context->m_lsSettings.m_nFileMethodID = FL2KB_METHOD_ID;
510                    context->m_lsSettings.m_nUDSMethodID  = FL2KB_METHOD_ID;
511                    break;
512                case SCHNEIER_METHOD_ID:
513                    context->m_lsSettings.m_nFileMethodID = SCHNEIER_METHOD_ID;
514                    context->m_lsSettings.m_nUDSMethodID  = SCHNEIER_METHOD_ID;
515                    break;
516                default:
517                    {
518                        LibrarySettings lsTemp;
519                        BOOL bExist = FALSE;
520                        if (loadLibrarySettings(&lsTemp))
521                        {
522                            for(int i = 0; i < lsTemp.m_nCMethods; i++)
523                                if (lsTemp.m_lpCMethods->m_nMethodID == param2) bExist = TRUE;
524                            if (bExist) {
525                                context->m_lsSettings.m_nFileMethodID = param2;
526                                context->m_lsSettings.m_nUDSMethodID  = param2;
527                            }
528                            else { 
529                                //eraserDestroyContext(*param1);
530                                lRetStatus = ERASER_ERROR_PARAM2;
531                                //break;
532                            }
533                        }
534                        else{
535                            //eraserDestroyContext(*param1);
536                            lRetStatus = ERASER_ERROR_PARAM2;
537                            //break;
538                        }
539                    }
540                }
541
542                return lRetStatus;
543            }
544            return ERASER_ERROR_CONTEXT;
545
546        } catch (...) {
547            ASSERT(0);
548            try {
549                eraserDestroyContext(*param1);
550            } catch (...) {
551            }
552            return ERASER_ERROR_EXCEPTION;
553        }
554    }
555}
556
557ERASER_EXPORT
558eraserDestroyContext(E_IN ERASER_HANDLE param1)
559{
560    AFX_MANAGE_STATE(AfxGetStaticModuleState());
561    eraserTraceBase("eraserDestroyContext\n");
562    if (!eraserIsLibraryInit()) {
563        return ERASER_ERROR_INIT;
564    }
565
566    CEraserContext *context = 0;
567    if (eraserError(contextToAddress(param1, &context))) {
568        return ERASER_ERROR_PARAM1;
569    } else {
570        try {
571            // make sure we are not running this one
572            VERIFY(eraserOK(eraserStop(param1)));
573            // remove from array
574            eraserContextArrayAccess();
575            eraserContextArray[eraserContextIndex(param1)] = 0;
576            eraserContextArrayRelease();
577            // free the memory
578            eraserContextLock(context);
579            delete context;
580            context = 0;
581        } catch (...) {
582            ASSERT(0);
583            return ERASER_ERROR_EXCEPTION;
584        }
585        return ERASER_OK;
586    }
587}
588
589ERASER_EXPORT
590eraserIsValidContext(E_IN ERASER_HANDLE param1)
591{
592    AFX_MANAGE_STATE(AfxGetStaticModuleState());
593    eraserTraceQuery("eraserIsValidContext\n");
594    if (!eraserIsLibraryInit()) {
595        return ERASER_ERROR_INIT;
596    }
597
598    CEraserContext *context = 0;
599    if (eraserError(contextToAddress(param1, &context))) {
600        return ERASER_ERROR_PARAM1;
601    } else {
602        return ERASER_OK;
603    }
604}
605//Error handler
606ERASER_EXPORT
607eraserSetErrorHandler(E_IN ERASER_HANDLE param1, EraserErrorHandler pfn, void* fnParam)
608{
609    CEraserContext *context = 0;
610    if (eraserError(contextToAddress(param1, &context))) 
611    {
612        return ERASER_ERROR_PARAM1;
613    } 
614    else if (eraserInternalIsRunning(context)) 
615    {
616        return ERASER_ERROR_RUNNING;
617    } 
618    else 
619    {
620        try 
621        {
622
623            eraserContextAccess(context);
624            context->m_pfnErrorHandler = pfn;
625            context->m_pErrorHandlerParam = fnParam;
626
627
628        } 
629        catch (...) 
630        {
631            ASSERT(0);
632            return ERASER_ERROR_EXCEPTION;
633        }
634        return ERASER_OK;
635    }
636
637}
638
639// Data type
640//
641ERASER_EXPORT
642eraserSetDataType(E_IN ERASER_HANDLE param1, E_IN ERASER_DATA_TYPE param2)
643{
644    AFX_MANAGE_STATE(AfxGetStaticModuleState());
645    eraserTraceBase("eraserSetDataType\n");
646    if (!eraserIsLibraryInit()) {
647        return ERASER_ERROR_INIT;
648    }
649
650    CEraserContext *context = 0;
651    if (!eraserIsValidDataType(param2)) {
652        return ERASER_ERROR_PARAM2;
653    } else if (eraserError(contextToAddress(param1, &context))) {
654        return ERASER_ERROR_PARAM1;
655    } else if (eraserInternalIsRunning(context)) {
656        return ERASER_ERROR_RUNNING;
657    } else {
658        try {
659            eraserContextAccess(context);
660            if (context->m_saData.GetSize() == 0) {
661                context->m_edtDataType = param2;
662            } else {
663                // cannot change data type after adding items to erase
664                return ERASER_ERROR_DENIED;
665            }
666        } catch (...) {
667            ASSERT(0);
668            return ERASER_ERROR_EXCEPTION;
669        }
670        return ERASER_OK;
671    }
672}
673
674ERASER_EXPORT
675eraserGetDataType(E_IN ERASER_HANDLE param1, E_OUT ERASER_DATA_TYPE *param2)
676{
677    AFX_MANAGE_STATE(AfxGetStaticModuleState());
678    eraserTraceQuery("eraserGetDataType\n");
679    if (!eraserIsLibraryInit()) {
680        return ERASER_ERROR_INIT;
681    }
682
683    CEraserContext *context = 0;
684    if (!AfxIsValidAddress(param2, sizeof(ERASER_DATA_TYPE))) {
685        return ERASER_ERROR_PARAM2;
686    } else if (eraserError(contextToAddress(param1, &context))) {
687        return ERASER_ERROR_PARAM1;
688    } else {
689        try {
690            eraserContextAccess(context);
691            *param2 = context->m_edtDataType;
692        } catch (...) {
693            ASSERT(0);
694            return ERASER_ERROR_EXCEPTION;
695        }
696        return ERASER_OK;
697    }
698}
699
700
701// Assign data
702//
703ERASER_EXPORT
704eraserAddItem(E_IN ERASER_HANDLE param1, E_IN LPVOID param2, E_IN E_UINT16 param3)
705{
706    AFX_MANAGE_STATE(AfxGetStaticModuleState());
707    eraserTraceBase("eraserAddItem\n");
708    if (!eraserIsLibraryInit()) {
709        return ERASER_ERROR_INIT;
710    }
711
712    CEraserContext *context = 0;
713    if (param3 < _MAX_DRIVE || param3 > _MAX_PATH) {
714        return ERASER_ERROR_PARAM3;
715    } else if (!AfxIsValidString((LPCTSTR)param2, param3)) {
716        return ERASER_ERROR_PARAM2;
717    } else if (eraserError(contextToAddress(param1, &context))) {
718        return ERASER_ERROR_PARAM1;
719    } else if (eraserInternalIsRunning(context)) {
720        return ERASER_ERROR_RUNNING;
721    } else {
722        try {
723            LPCTSTR szItem = (LPCTSTR)param2;
724
725            // if the item is a file, a fully qualified name is required,
726            // drive must be given as "X:\\"
727
728            if (!isalpha(szItem[0]) || szItem[1] != ':' || szItem[2] != '\\') {
729                return ERASER_ERROR_PARAM2;
730            }
731
732            eraserContextAccess(context);
733
734            if ((context->m_edtDataType == ERASER_DATA_FILES  && strlen(szItem) > _MAX_PATH) ||
735                (context->m_edtDataType == ERASER_DATA_DRIVES && strlen(szItem) > _MAX_DRIVE)) {
736                return ERASER_ERROR_PARAM2;
737            } else {
738                context->m_saData.Add(szItem);
739            }
740        } catch (...) {
741            ASSERT(0);
742            return ERASER_ERROR_EXCEPTION;
743        }
744        return ERASER_OK;
745    }
746}
747
748ERASER_EXPORT
749eraserSetFinishAction(E_IN ERASER_HANDLE param1, E_IN DWORD action)
750{
751    CEraserContext *context = 0;
752    if (eraserError(contextToAddress(param1, &context))) {
753        return ERASER_ERROR_PARAM1;
754    } else if (eraserInternalIsRunning(context)) {
755        return ERASER_ERROR_RUNNING;
756    } else {
757        try {
758           
759            eraserContextAccess(context);
760            context->m_dwFinishAction = action;
761
762           
763        } catch (...) {
764            ASSERT(0);
765            return ERASER_ERROR_EXCEPTION;
766        }
767        return ERASER_OK;
768    }
769
770}
771ERASER_EXPORT
772eraserClearItems(E_IN ERASER_HANDLE param1)
773{
774    AFX_MANAGE_STATE(AfxGetStaticModuleState());
775    eraserTraceBase("eraserClearItems\n");
776    if (!eraserIsLibraryInit()) {
777        return ERASER_ERROR_INIT;
778    }
779
780    CEraserContext *context = 0;
781    if (eraserError(contextToAddress(param1, &context))) {
782        return ERASER_ERROR_PARAM1;
783    } else if (eraserInternalIsRunning(context)) {
784        return ERASER_ERROR_RUNNING;
785    } else {
786        try {
787            eraserContextAccess(context);
788            context->m_saData.RemoveAll();
789        } catch (...) {
790            ASSERT(0);
791            return ERASER_ERROR_EXCEPTION;
792        }
793        return ERASER_OK;
794    }
795}
796
797
798// Notification
799//
800ERASER_EXPORT
801eraserSetWindow(E_IN ERASER_HANDLE param1, E_IN HWND param2)
802{
803    AFX_MANAGE_STATE(AfxGetStaticModuleState());
804    eraserTraceBase("eraserSetWindow\n");
805    if (!eraserIsLibraryInit()) {
806        return ERASER_ERROR_INIT;
807    }
808
809    CEraserContext *context = 0;
810    if (!IsWindow(param2)) {
811        return ERASER_ERROR_PARAM2;
812    } else if (eraserError(contextToAddress(param1, &context))) {
813        return ERASER_ERROR_PARAM1;
814    } else {
815        try {
816            eraserContextAccess(context);
817            context->m_hwndWindow = param2;
818        } catch (...) {
819            ASSERT(0);
820            return ERASER_ERROR_EXCEPTION;
821        }
822        return ERASER_OK;
823    }
824}
825
826ERASER_EXPORT
827eraserGetWindow(E_IN ERASER_HANDLE param1, E_OUT HWND* param2)
828{
829    AFX_MANAGE_STATE(AfxGetStaticModuleState());
830    eraserTraceQuery("eraserGetWindow\n");
831    if (!eraserIsLibraryInit()) {
832        return ERASER_ERROR_INIT;
833    }
834
835    CEraserContext *context = 0;
836    if (!AfxIsValidAddress(param2, sizeof(HWND))) {
837        return ERASER_ERROR_PARAM2;
838    } else if (eraserError(contextToAddress(param1, &context))) {
839        return ERASER_ERROR_PARAM1;
840    } else {
841        try {
842            eraserContextAccess(context);
843            *param2 = context->m_hwndWindow;
844        } catch (...) {
845            ASSERT(0);
846            return ERASER_ERROR_EXCEPTION;
847        }
848        return ERASER_OK;
849    }
850}
851
852ERASER_EXPORT
853eraserSetWindowMessage(E_IN ERASER_HANDLE param1, E_IN E_UINT32 param2)
854{
855    AFX_MANAGE_STATE(AfxGetStaticModuleState());
856    eraserTraceBase("eraserSetWindowMessage\n");
857    if (!eraserIsLibraryInit()) {
858        return ERASER_ERROR_INIT;
859    }
860
861    CEraserContext *context = 0;
862    if (eraserError(contextToAddress(param1, &context))) {
863        return ERASER_ERROR_PARAM1;
864    } else {
865        try {
866            eraserContextAccess(context);
867            context->m_uWindowMessage = param2;
868        } catch (...) {
869            ASSERT(0);
870            return ERASER_ERROR_EXCEPTION;
871        }
872        return ERASER_OK;
873    }
874}
875
876ERASER_EXPORT
877eraserGetWindowMessage(E_IN ERASER_HANDLE param1, E_OUT E_PUINT32 param2)
878{
879    AFX_MANAGE_STATE(AfxGetStaticModuleState());
880    eraserTraceQuery("eraserGetWindowMessage\n");
881    if (!eraserIsLibraryInit()) {
882        return ERASER_ERROR_INIT;
883    }
884
885    CEraserContext *context = 0;
886    if (!AfxIsValidAddress(param2, sizeof(E_UINT32))) {
887        return ERASER_ERROR_PARAM2;
888    } else if (eraserError(contextToAddress(param1, &context))) {
889        return ERASER_ERROR_PARAM1;
890    } else {
891        try {
892            eraserContextAccess(context);
893            *param2 = context->m_uWindowMessage;
894        } catch (...) {
895            ASSERT(0);
896            return ERASER_ERROR_EXCEPTION;
897        }
898        return ERASER_OK;
899    }
900}
901
902
903// Statistics
904//
905ERASER_EXPORT
906eraserStatGetArea(E_IN ERASER_HANDLE param1, E_OUT E_PUINT64 param2)
907{
908    AFX_MANAGE_STATE(AfxGetStaticModuleState());
909    eraserTraceProgress("eraserStatGetArea\n");
910    if (!eraserIsLibraryInit()) {
911        return ERASER_ERROR_INIT;
912    }
913
914    CEraserContext *context = 0;
915    if (!AfxIsValidAddress(param2, sizeof(E_UINT64))) {
916        return ERASER_ERROR_PARAM2;
917    } else if (eraserError(contextToAddress(param1, &context))) {
918        return ERASER_ERROR_PARAM1;
919    } else if (eraserInternalIsRunning(context)) {
920        return ERASER_ERROR_RUNNING;
921    } else {
922        try {
923            eraserContextAccess(context);
924            *param2 = context->m_uStatErasedArea;
925        } catch (...) {
926            ASSERT(0);
927            return ERASER_ERROR_EXCEPTION;
928        }
929        return ERASER_OK;
930    }
931}
932
933ERASER_EXPORT
934eraserStatGetTips(E_IN ERASER_HANDLE param1, E_OUT E_PUINT64 param2)
935{
936    AFX_MANAGE_STATE(AfxGetStaticModuleState());
937    eraserTraceProgress("eraserStatGetTips\n");
938    if (!eraserIsLibraryInit()) {
939        return ERASER_ERROR_INIT;
940    }
941
942    CEraserContext *context = 0;
943    if (!AfxIsValidAddress(param2, sizeof(E_UINT64))) {
944        return ERASER_ERROR_PARAM2;
945    } else if (eraserError(contextToAddress(param1, &context))) {
946        return ERASER_ERROR_PARAM1;
947    } else if (eraserInternalIsRunning(context)) {
948        return ERASER_ERROR_RUNNING;
949    } else {
950        try {
951            eraserContextAccess(context);
952            *param2 = context->m_uStatTips;
953        } catch (...) {
954            ASSERT(0);
955            return ERASER_ERROR_EXCEPTION;
956        }
957        return ERASER_OK;
958    }
959}
960
961ERASER_EXPORT
962eraserStatGetWiped(E_IN ERASER_HANDLE param1, E_OUT E_PUINT64 param2)
963{
964    AFX_MANAGE_STATE(AfxGetStaticModuleState());
965    eraserTraceProgress("eraserStatGetWiped\n");
966    if (!eraserIsLibraryInit()) {
967        return ERASER_ERROR_INIT;
968    }
969
970    CEraserContext *context = 0;
971    if (!AfxIsValidAddress(param2, sizeof(E_UINT64))) {
972        return ERASER_ERROR_PARAM2;
973    } else if (eraserError(contextToAddress(param1, &context))) {
974        return ERASER_ERROR_PARAM1;
975    } else if (eraserInternalIsRunning(context)) {
976        return ERASER_ERROR_RUNNING;
977    } else {
978        try {
979            eraserContextAccess(context);
980            *param2 = context->m_uStatWiped;
981        } catch (...) {
982            ASSERT(0);
983            return ERASER_ERROR_EXCEPTION;
984        }
985        return ERASER_OK;
986    }
987}
988
989ERASER_EXPORT
990eraserStatGetTime(E_IN ERASER_HANDLE param1, E_OUT E_PUINT32 param2)
991{
992    AFX_MANAGE_STATE(AfxGetStaticModuleState());
993    eraserTraceProgress("eraserStatGetTime\n");
994    if (!eraserIsLibraryInit()) {
995        return ERASER_ERROR_INIT;
996    }
997
998    CEraserContext *context = 0;
999    if (!AfxIsValidAddress(param2, sizeof(E_UINT32))) {
1000        return ERASER_ERROR_PARAM2;
1001    } else if (eraserError(contextToAddress(param1, &context))) {
1002        return ERASER_ERROR_PARAM1;
1003    } else if (eraserInternalIsRunning(context)) {
1004        return ERASER_ERROR_RUNNING;
1005    } else {
1006        try {
1007            eraserContextAccess(context);
1008            *param2 = context->m_uStatTime;
1009        } catch (...) {
1010            ASSERT(0);
1011            return ERASER_ERROR_EXCEPTION;
1012        }
1013        return ERASER_OK;
1014    }
1015}
1016
1017
1018// Display
1019//
1020ERASER_EXPORT
1021eraserDispFlags(E_IN ERASER_HANDLE param1, E_OUT E_PUINT8 param2)
1022{
1023    AFX_MANAGE_STATE(AfxGetStaticModuleState());
1024    eraserTraceProgress("eraserDispFlags\n");
1025    if (!eraserIsLibraryInit()) {
1026        return ERASER_ERROR_INIT;
1027    }
1028
1029    CEraserContext *context = 0;
1030    if (!AfxIsValidAddress(param2, sizeof(E_UINT8))) {
1031        return ERASER_ERROR_PARAM2;
1032    } else if (eraserError(contextToAddress(param1, &context))) {
1033        return ERASER_ERROR_PARAM1;
1034    } else if (!eraserInternalIsRunning(context)) {
1035        return ERASER_ERROR_NOTRUNNING;
1036    } else {
1037        try {
1038            eraserContextAccess(context);
1039            // low-order byte
1040            *param2 = (E_UINT8)context->m_uProgressFlags;
1041        } catch (...) {
1042            ASSERT(0);
1043            return ERASER_ERROR_EXCEPTION;
1044        }
1045        return ERASER_OK;
1046    }
1047}
1048
1049
1050// Progress information
1051//
1052ERASER_EXPORT
1053eraserProgGetTimeLeft(E_IN ERASER_HANDLE param1, E_OUT E_PUINT32 param2)
1054{
1055    AFX_MANAGE_STATE(AfxGetStaticModuleState());
1056    eraserTraceProgress("eraserProgGetTimeLeft\n");
1057    if (!eraserIsLibraryInit()) {
1058        return ERASER_ERROR_INIT;
1059    }
1060
1061    CEraserContext *context = 0;
1062    if (!AfxIsValidAddress(param2, sizeof(E_UINT32))) {
1063        return ERASER_ERROR_PARAM2;
1064    } else if (eraserError(contextToAddress(param1, &context))) {
1065        return ERASER_ERROR_PARAM1;
1066    } else if (!eraserInternalIsRunning(context)) {
1067        return ERASER_ERROR_NOTRUNNING;
1068    } else {
1069        try {
1070            eraserContextAccess(context);
1071            *param2 = context->m_uProgressTimeLeft;
1072        } catch (...) {
1073            ASSERT(0);
1074            return ERASER_ERROR_EXCEPTION;
1075        }
1076        return ERASER_OK;
1077    }
1078}
1079
1080ERASER_EXPORT
1081eraserProgGetPercent(E_IN ERASER_HANDLE param1, E_OUT E_PUINT8 param2)
1082{
1083    AFX_MANAGE_STATE(AfxGetStaticModuleState());
1084    eraserTraceProgress("eraserProgGetPercent\n");
1085    if (!eraserIsLibraryInit()) {
1086        return ERASER_ERROR_INIT;
1087    }
1088
1089    CEraserContext *context = 0;
1090    if (!AfxIsValidAddress(param2, sizeof(E_UINT8))) {
1091        return ERASER_ERROR_PARAM2;
1092    } else if (eraserError(contextToAddress(param1, &context))) {
1093        return ERASER_ERROR_PARAM1;
1094    } else if (!eraserInternalIsRunning(context)) {
1095        return ERASER_ERROR_NOTRUNNING;
1096    } else {
1097        try {
1098            eraserContextAccess(context);
1099            *param2 = min(context->m_uProgressPercent, (E_UINT8)100);
1100        } catch (...) {
1101            ASSERT(0);
1102            return ERASER_ERROR_EXCEPTION;
1103        }
1104        return ERASER_OK;
1105    }
1106}
1107
1108ERASER_EXPORT
1109eraserProgGetTotalPercent(E_IN ERASER_HANDLE param1, E_OUT E_PUINT8 param2)
1110{
1111    AFX_MANAGE_STATE(AfxGetStaticModuleState());
1112    eraserTraceProgress("eraserProgGetTotalPercent\n");
1113    if (!eraserIsLibraryInit()) {
1114        return ERASER_ERROR_INIT;
1115    }
1116
1117    CEraserContext *context = 0;
1118    if (!AfxIsValidAddress(param2, sizeof(E_UINT8))) {
1119        return ERASER_ERROR_PARAM2;
1120    } else if (eraserError(contextToAddress(param1, &context))) {
1121        return ERASER_ERROR_PARAM1;
1122    } else if (!eraserInternalIsRunning(context)) {
1123        return ERASER_ERROR_NOTRUNNING;
1124    } else {
1125        try {
1126            eraserContextAccess(context);
1127            *param2 = min(context->m_uProgressTotalPercent, (E_UINT8)100);
1128        } catch (...) {
1129            ASSERT(0);
1130            return ERASER_ERROR_EXCEPTION;
1131        }
1132        return ERASER_OK;
1133    }
1134}
1135
1136ERASER_EXPORT
1137eraserProgGetCurrentPass(E_IN ERASER_HANDLE param1, E_OUT E_PUINT16 param2)
1138{
1139    AFX_MANAGE_STATE(AfxGetStaticModuleState());
1140    eraserTraceProgress("eraserProgGetCurrentPass\n");
1141    if (!eraserIsLibraryInit()) {
1142        return ERASER_ERROR_INIT;
1143    }
1144
1145    CEraserContext *context = 0;
1146    if (!AfxIsValidAddress(param2, sizeof(E_UINT16))) {
1147        return ERASER_ERROR_PARAM2;
1148    } else if (eraserError(contextToAddress(param1, &context))) {
1149        return ERASER_ERROR_PARAM1;
1150    } else if (!eraserInternalIsRunning(context)) {
1151        return ERASER_ERROR_NOTRUNNING;
1152    } else {
1153        try {
1154            eraserContextAccess(context);
1155            *param2 = context->m_uProgressCurrentPass;
1156        } catch (...) {
1157            ASSERT(0);
1158            return ERASER_ERROR_EXCEPTION;
1159        }
1160        return ERASER_OK;
1161    }
1162}
1163
1164ERASER_EXPORT
1165eraserProgGetPasses(E_IN ERASER_HANDLE param1, E_OUT E_PUINT16 param2)
1166{
1167    AFX_MANAGE_STATE(AfxGetStaticModuleState());
1168    eraserTraceProgress("eraserProgGetPasses\n");
1169    if (!eraserIsLibraryInit()) {
1170        return ERASER_ERROR_INIT;
1171    }
1172
1173    CEraserContext *context = 0;
1174    if (!AfxIsValidAddress(param2, sizeof(E_UINT16))) {
1175        return ERASER_ERROR_PARAM2;
1176    } else if (eraserError(contextToAddress(param1, &context))) {
1177        return ERASER_ERROR_PARAM1;
1178    } else if (!eraserInternalIsRunning(context)) {
1179        return ERASER_ERROR_NOTRUNNING;
1180    } else {
1181        try {
1182            eraserContextAccess(context);
1183            *param2 = context->m_uProgressPasses;
1184        } catch (...) {
1185            ASSERT(0);
1186            return ERASER_ERROR_EXCEPTION;
1187        }
1188        return ERASER_OK;
1189    }
1190}
1191
1192ERASER_EXPORT
1193eraserProgGetMessage(E_IN ERASER_HANDLE param1, E_OUT LPVOID param2, E_INOUT E_PUINT16 param3)
1194{
1195    AFX_MANAGE_STATE(AfxGetStaticModuleState());
1196    eraserTraceProgress("eraserProgGetMessage\n");
1197    if (!eraserIsLibraryInit()) {
1198        return ERASER_ERROR_INIT;
1199    }
1200
1201    CEraserContext *context = 0;
1202    if (!AfxIsValidAddress(param3, sizeof(E_UINT16))) {
1203        return ERASER_ERROR_PARAM3;
1204    } else if (eraserError(contextToAddress(param1, &context))) {
1205        return ERASER_ERROR_PARAM1;
1206    } else if (!eraserInternalIsRunning(context)) {
1207        return ERASER_ERROR_NOTRUNNING;
1208    } else {
1209        try {
1210            eraserContextAccess(context);
1211            LPTSTR pszError = (LPTSTR)param2;
1212            if (pszError == 0) {
1213                *param3 = (E_UINT16)(context->m_strProgressMessage.GetLength() + 1);
1214                return ERASER_OK;
1215            } else if (*param3 < 1) {
1216                return ERASER_ERROR_PARAM3;
1217            } else if (!AfxIsValidAddress((LPCTSTR)pszError, *param3)) {
1218                return ERASER_ERROR_PARAM2;
1219            }
1220            ZeroMemory(pszError, *param3);
1221            lstrcpyn(pszError, (LPCTSTR)context->m_strProgressMessage, *param3);
1222        } catch (...) {
1223            ASSERT(0);
1224            return ERASER_ERROR_EXCEPTION;
1225        }
1226        return ERASER_OK;
1227    }
1228}
1229
1230ERASER_EXPORT
1231eraserProgGetCurrentDataString(E_IN ERASER_HANDLE param1, E_OUT LPVOID param2, E_INOUT E_PUINT16 param3)
1232{
1233    AFX_MANAGE_STATE(AfxGetStaticModuleState());
1234    eraserTraceProgress("eraserProgGetCurrentDataString\n");
1235    if (!eraserIsLibraryInit()) {
1236        return ERASER_ERROR_INIT;
1237    }
1238
1239    CEraserContext *context = 0;
1240    if (!AfxIsValidAddress(param3, sizeof(E_UINT16))) {
1241        return ERASER_ERROR_PARAM3;
1242    } else if (eraserError(contextToAddress(param1, &context))) {
1243        return ERASER_ERROR_PARAM1;
1244    } else if (!eraserInternalIsRunning(context)) {
1245        return ERASER_ERROR_NOTRUNNING;
1246    } else {
1247        try {
1248            eraserContextAccess(context);
1249            LPTSTR pszError = (LPTSTR)param2;
1250            if (pszError == 0) {
1251                *param3 = (E_UINT16)(context->m_strData.GetLength() + 1);
1252                return ERASER_OK;
1253            } else if (*param3 < 1) {
1254                return ERASER_ERROR_PARAM3;
1255            } else if (!AfxIsValidAddress((LPCTSTR)pszError, *param3)) {
1256                return ERASER_ERROR_PARAM2;
1257            }
1258            ZeroMemory(pszError, *param3);
1259            lstrcpyn(pszError, (LPCTSTR)context->m_strData, *param3);
1260        } catch (...) {
1261            ASSERT(0);
1262            return ERASER_ERROR_EXCEPTION;
1263        }
1264        return ERASER_OK;
1265    }
1266}
1267
1268
1269// Control
1270//
1271ERASER_EXPORT
1272eraserStart(E_IN ERASER_HANDLE param1)
1273{
1274    AFX_MANAGE_STATE(AfxGetStaticModuleState());
1275    eraserTraceBase("eraserStart\n");
1276    if (!eraserIsLibraryInit()) {
1277        return ERASER_ERROR_INIT;
1278    }
1279
1280    CEraserContext *context = 0;
1281    if (eraserError(contextToAddress(param1, &context))) {
1282        return ERASER_ERROR_PARAM1;
1283    } else if (eraserInternalIsRunning(context)) {
1284        return ERASER_ERROR_RUNNING;
1285    } else {
1286        try {
1287            eraserContextAccess(context);
1288            // preset flags
1289            context->m_evDone.SetEvent();
1290            context->m_evKillThread.ResetEvent();
1291            // create the thread
1292            context->m_pwtThread = AfxBeginThread(eraserThread, (LPVOID)context);
1293            if (context->m_pwtThread == NULL) {
1294                return ERASER_ERROR_THREAD;
1295            }
1296            // start operation
1297            eraserContextRelease();
1298            context->m_evStart.SetEvent();
1299        } catch (...) {
1300            ASSERT(0);
1301            eraserStop(param1);
1302            return ERASER_ERROR_EXCEPTION;
1303        }
1304        return ERASER_OK;
1305    }
1306}
1307
1308ERASER_EXPORT
1309eraserStartSync(E_IN ERASER_HANDLE param1)
1310{
1311    AFX_MANAGE_STATE(AfxGetStaticModuleState());
1312    eraserTraceBase("eraserStartSync\n");
1313    if (!eraserIsLibraryInit()) {
1314        return ERASER_ERROR_INIT;
1315    }
1316
1317    CEraserContext *context = 0;
1318    if (eraserError(contextToAddress(param1, &context))) {
1319        return ERASER_ERROR_PARAM1;
1320    } else if (eraserInternalIsRunning(context)) {
1321        return ERASER_ERROR_RUNNING;
1322    } else {
1323        try {
1324            eraserContextAccess(context);
1325            // preset flags
1326            context->m_evDone.SetEvent();
1327            context->m_evKillThread.ResetEvent();
1328            context->m_evStart.SetEvent();
1329            eraserContextRelease();
1330            // start erasing
1331            if (eraserThread((LPVOID)context) == EXIT_SUCCESS) {
1332                return ERASER_OK;
1333            } else {
1334                return ERASER_ERROR;
1335            }
1336        } catch (...) {
1337            ASSERT(0);
1338            return ERASER_ERROR_EXCEPTION;
1339        }
1340    }
1341}
1342
1343
1344ERASER_EXPORT
1345eraserStop(E_IN ERASER_HANDLE param1)
1346{
1347    AFX_MANAGE_STATE(AfxGetStaticModuleState());
1348    eraserTraceBase("eraserStop\n");
1349    if (!eraserIsLibraryInit()) {
1350        return ERASER_ERROR_INIT;
1351    }
1352
1353    CEraserContext *context = 0;
1354    if (eraserError(contextToAddress(param1, &context))) {
1355        return ERASER_ERROR_PARAM1;
1356    } else {
1357        try {
1358            // set the kill flag
1359            context->m_evKillThread.SetEvent();
1360            context->m_evStart.SetEvent();
1361            // if in test mode, enable execution again
1362            eraserContextAccess(context);
1363            if (context->m_uTestMode) {
1364                context->m_evTestContinue.SetEvent();
1365            }
1366            eraserContextRelease();
1367            // two minutes should be enough for any thread (don't quote me)
1368            if (WaitForSingleObject(context->m_evThreadKilled, 120000) != WAIT_OBJECT_0) {
1369                // if the thread is still active, just kill it
1370                eraserContextRelock();
1371                if (AfxIsValidAddress(context->m_pwtThread, sizeof(CWinThread))) {
1372                    E_UINT32 uStatus = 0;
1373                    if (::GetExitCodeThread(context->m_pwtThread->m_hThread, &uStatus) &&
1374                        uStatus == STILL_ACTIVE) {
1375                        VERIFY(::TerminateThread(context->m_pwtThread->m_hThread, (E_UINT32)ERASER_ERROR));
1376                    }
1377                }
1378                context->m_evThreadKilled.SetEvent();
1379            }
1380            eraserContextRelock();
1381            context->m_pwtThread = 0;
1382        } catch (...) {
1383            ASSERT(0);
1384            return ERASER_ERROR_EXCEPTION;
1385        }
1386        return ERASER_OK;
1387    }
1388}
1389
1390ERASER_EXPORT
1391eraserIsRunning(E_IN ERASER_HANDLE param1, E_OUT E_PUINT8 param2)
1392{
1393    AFX_MANAGE_STATE(AfxGetStaticModuleState());
1394    eraserTraceQuery("eraserIsRunning\n");
1395    if (!eraserIsLibraryInit()) {
1396        return ERASER_ERROR_INIT;
1397    }
1398
1399    CEraserContext *context = 0;
1400    if (!AfxIsValidAddress(param2, sizeof(E_UINT8))) {
1401        return ERASER_ERROR_PARAM2;
1402    } else if (eraserError(contextToAddress(param1, &context))) {
1403        return ERASER_ERROR_PARAM1;
1404    } else {
1405        try {
1406            eraserContextAccess(context);
1407            *param2 = 0;
1408            if (eraserInternalIsRunning(context)) {
1409                *param2 = 1;
1410            }
1411        } catch (...) {
1412            ASSERT(0);
1413            return ERASER_ERROR_EXCEPTION;
1414        }
1415        return ERASER_OK;
1416    }
1417}
1418
1419// Result
1420//
1421ERASER_EXPORT
1422eraserTerminated(E_IN ERASER_HANDLE param1, E_OUT E_PUINT8 param2)
1423{
1424    AFX_MANAGE_STATE(AfxGetStaticModuleState());
1425    eraserTraceQuery("eraserTerminated\n");
1426    if (!eraserIsLibraryInit()) {
1427        return ERASER_ERROR_INIT;
1428    }
1429
1430    CEraserContext *context = 0;
1431    if (!AfxIsValidAddress(param2, sizeof(E_UINT8))) {
1432        return ERASER_ERROR_PARAM2;
1433    } else if (eraserError(contextToAddress(param1, &context))) {
1434        return ERASER_ERROR_PARAM1;
1435    } else if (eraserInternalIsRunning(context)) {
1436        return ERASER_ERROR_RUNNING;
1437    } else {
1438        try {
1439            eraserContextAccess(context);
1440            *param2 = 0;
1441            if (eraserInternalTerminated(context)) {
1442                *param2 = 1;
1443            }
1444        } catch (...) {
1445            ASSERT(0);
1446            return ERASER_ERROR_EXCEPTION;
1447        }
1448        return ERASER_OK;
1449    }
1450}
1451
1452ERASER_EXPORT
1453eraserCompleted(E_IN ERASER_HANDLE param1, E_OUT E_PUINT8 param2)
1454{
1455    AFX_MANAGE_STATE(AfxGetStaticModuleState());
1456    eraserTraceQuery("eraserCompleted\n");
1457    if (!eraserIsLibraryInit()) {
1458        return ERASER_ERROR_INIT;
1459    }
1460
1461    CEraserContext *context = 0;
1462    if (!AfxIsValidAddress(param2, sizeof(E_UINT8))) {
1463        return ERASER_ERROR_PARAM2;
1464    } else if (eraserError(contextToAddress(param1, &context))) {
1465        return ERASER_ERROR_PARAM1;
1466    } else if (eraserInternalIsRunning(context)) {
1467        return ERASER_ERROR_RUNNING;
1468    } else {
1469        try {
1470            eraserContextAccess(context);
1471            *param2 = 0;
1472            if (eraserInternalCompleted(context)) {
1473                *param2 = 1;
1474            }
1475        } catch (...) {
1476            ASSERT(0);
1477            return ERASER_ERROR_EXCEPTION;
1478        }
1479        return ERASER_OK;
1480    }
1481}
1482
1483ERASER_EXPORT
1484eraserFailed(E_IN ERASER_HANDLE param1, E_OUT E_PUINT8 param2)
1485{
1486    AFX_MANAGE_STATE(AfxGetStaticModuleState());
1487    eraserTraceQuery("eraserFailed\n");
1488    ERASER_RESULT result = eraserCompleted(param1, param2);
1489
1490    if (eraserOK(result)) {
1491        try {
1492            if (*param2) {
1493                *param2 = 0;
1494            } else {
1495                *param2 = 1;
1496            }
1497        } catch (...) {
1498            ASSERT(0);
1499            return ERASER_ERROR_EXCEPTION;
1500        }
1501    }
1502
1503    return result;
1504}
1505
1506ERASER_EXPORT
1507eraserErrorStringCount(E_IN ERASER_HANDLE param1, E_OUT E_PUINT16 param2)
1508{
1509    AFX_MANAGE_STATE(AfxGetStaticModuleState());
1510    eraserTraceQuery("eraserErrorStringCount\n");
1511    if (!eraserIsLibraryInit()) {
1512        return ERASER_ERROR_INIT;
1513    }
1514
1515    CEraserContext *context = 0;
1516    if (!AfxIsValidAddress(param2, sizeof(E_UINT16))) {
1517        return ERASER_ERROR_PARAM2;
1518    } else if (eraserError(contextToAddress(param1, &context))) {
1519        return ERASER_ERROR_PARAM1;
1520    } else if (eraserInternalIsRunning(context)) {
1521        return ERASER_ERROR_RUNNING;
1522    } else {
1523        try {
1524            eraserContextAccess(context);
1525            *param2 = (E_UINT16)context->m_saError.GetSize();
1526        } catch (...) {
1527            ASSERT(0);
1528            return ERASER_ERROR_EXCEPTION;
1529        }
1530        return ERASER_OK;
1531    }
1532}
1533
1534ERASER_EXPORT
1535eraserErrorString(E_IN ERASER_HANDLE param1, E_IN E_UINT16 param2, E_OUT LPVOID param3, E_INOUT E_PUINT16 param4)
1536{
1537    AFX_MANAGE_STATE(AfxGetStaticModuleState());
1538    eraserTraceQuery("eraserErrorString\n");
1539    if (!eraserIsLibraryInit()) {
1540        return ERASER_ERROR_INIT;
1541    }
1542
1543    CEraserContext *context = 0;
1544    if (!AfxIsValidAddress(param4, sizeof(E_UINT16))) {
1545        return ERASER_ERROR_PARAM4;
1546    } else if (eraserError(contextToAddress(param1, &context))) {
1547        return ERASER_ERROR_PARAM1;
1548    } else if (eraserInternalIsRunning(context)) {
1549        return ERASER_ERROR_RUNNING;
1550    } else {
1551        try {
1552            eraserContextAccess(context);
1553            if (context->m_saError.GetSize() <= param2) {
1554                return ERASER_ERROR_PARAM2;
1555            }
1556            LPTSTR pszError = (LPTSTR)param3;
1557            if (pszError == 0) {
1558                *param4 = (E_UINT16)(context->m_saError[param2].GetLength() + 1);
1559                return ERASER_OK;
1560            } else if (*param4 < 1) {
1561                return ERASER_ERROR_PARAM4;
1562            } else if (!AfxIsValidAddress((LPCTSTR)pszError, *param4)) {
1563                return ERASER_ERROR_PARAM3;
1564            }
1565            ZeroMemory(pszError, *param4);
1566            lstrcpyn(pszError, (LPCTSTR)context->m_saError[param2], *param4);
1567        } catch (...) {
1568            ASSERT(0);
1569            return ERASER_ERROR_EXCEPTION;
1570        }
1571        return ERASER_OK;
1572    }
1573}
1574
1575ERASER_EXPORT
1576eraserFailedCount(E_IN ERASER_HANDLE param1, E_OUT E_PUINT32 param2)
1577{
1578    AFX_MANAGE_STATE(AfxGetStaticModuleState());
1579    eraserTraceQuery("eraserFailedCount\n");
1580    if (!eraserIsLibraryInit()) {
1581        return ERASER_ERROR_INIT;
1582    }
1583
1584    CEraserContext *context = 0;
1585    if (!AfxIsValidAddress(param2, sizeof(E_UINT32))) {
1586        return ERASER_ERROR_PARAM2;
1587    } else if (eraserError(contextToAddress(param1, &context))) {
1588        return ERASER_ERROR_PARAM1;
1589    } else if (eraserInternalIsRunning(context)) {
1590        return ERASER_ERROR_RUNNING;
1591    } else {
1592        try {
1593            eraserContextAccess(context);
1594            *param2 = (E_UINT32)context->m_saFailed.GetSize();
1595        } catch (...) {
1596            ASSERT(0);
1597            return ERASER_ERROR_EXCEPTION;
1598        }
1599        return ERASER_OK;
1600    }
1601}
1602
1603ERASER_EXPORT
1604eraserFailedString(E_IN ERASER_HANDLE param1, E_IN E_UINT32 param2, E_OUT LPVOID param3, E_INOUT E_PUINT16 param4)
1605{
1606    AFX_MANAGE_STATE(AfxGetStaticModuleState());
1607    eraserTraceQuery("eraserFailedString\n");
1608    if (!eraserIsLibraryInit()) {
1609        return ERASER_ERROR_INIT;
1610    }
1611
1612    CEraserContext *context = 0;
1613    if (!AfxIsValidAddress(param4, sizeof(E_UINT16))) {
1614        return ERASER_ERROR_PARAM4;
1615    } else if (eraserError(contextToAddress(param1, &context))) {
1616        return ERASER_ERROR_PARAM1;
1617    } else if (eraserInternalIsRunning(context)) {
1618        return ERASER_ERROR_RUNNING;
1619    } else {
1620        try {
1621            eraserContextAccess(context);
1622            if ((E_UINT32)context->m_saFailed.GetSize() <= param2) {
1623                return ERASER_ERROR_PARAM2;
1624            }
1625            LPTSTR pszError = (LPTSTR)param3;
1626            if (pszError == 0) {
1627                *param4 = (E_UINT16)(context->m_saFailed[param2].GetLength() + 1);
1628                return ERASER_OK;
1629            } else if (*param4 < 1) {
1630                return ERASER_ERROR_PARAM4;
1631            } else if (!AfxIsValidAddress((LPCTSTR)pszError, *param4)) {
1632                return ERASER_ERROR_PARAM3;
1633            }
1634            ZeroMemory(pszError, *param4);
1635            lstrcpyn(pszError, (LPCTSTR)context->m_saFailed[param2], *param4);
1636        } catch (...) {
1637            ASSERT(0);
1638            return ERASER_ERROR_EXCEPTION;
1639        }
1640        return ERASER_OK;
1641    }
1642}
1643
1644
1645// Display report
1646//
1647ERASER_EXPORT
1648eraserShowReport(E_IN ERASER_HANDLE param1, E_IN HWND param2)
1649{
1650    AFX_MANAGE_STATE(AfxGetStaticModuleState());
1651    eraserTraceBase("eraserShowReport\n");
1652    if (!eraserIsLibraryInit()) {
1653        return ERASER_ERROR_INIT;
1654    }
1655
1656    CEraserContext *context = 0;
1657    if (!IsWindow(param2)) {
1658        return ERASER_ERROR_PARAM2;
1659    } else if (eraserError(contextToAddress(param1, &context))) {
1660        return ERASER_ERROR_PARAM1;
1661    } else if (eraserInternalIsRunning(context)) {
1662        return ERASER_ERROR_RUNNING;
1663    }
1664
1665    ERASER_RESULT result = ERASER_OK;
1666    CWnd wndParent;
1667    wndParent.Attach(param2);
1668
1669    try {
1670        CStringArray straFailures;
1671        CString strTemp;
1672        CString strUnit;
1673        E_UINT32 uIndex, uSize;
1674        E_UINT64 uTemp;
1675        double dTime;
1676        CReportDialog rd;
1677
1678        // completion
1679        if (eraserInternalCompleted(context)) {
1680            rd.m_strCompletion = "Task completed.";
1681        } else if (eraserInternalTerminated(context)) {
1682            rd.m_strCompletion = "Task terminated by user.";
1683        } else {
1684            if (context->m_saError.GetSize() > 0) {
1685                rd.m_strCompletion = "Task was not completed.";
1686            } else {
1687                rd.m_strCompletion = "Task completed. All data could not be erased.";
1688            }
1689        }
1690
1691        #define reportMaxByteValue    (10 * 1024)
1692        #define reportMaxkBValue    (1000 * 1024)
1693       
1694        #define divideByK(value) \
1695            (value) = (((value) + 512) / 1024)
1696
1697        #define setValueAndUnit(value) \
1698            do { \
1699                uTemp = (value); \
1700                if (uTemp > reportMaxByteValue) { \
1701                    divideByK(uTemp); \
1702                    if (uTemp > reportMaxkBValue) { \
1703                        divideByK(uTemp); \
1704                        strUnit = "MB"; \
1705                    } else { \
1706                        strUnit = "kB"; \
1707                    } \
1708                } else { \
1709                    if ((value) != 1) { \
1710                        strUnit = "bytes"; \
1711                    } else { \
1712                        strUnit = "byte"; \
1713                    } \
1714                } \
1715            } while (0)
1716
1717        // information header
1718        rd.m_strStatistics = "Statistics:\r\n";
1719        // erased area
1720        setValueAndUnit(context->m_uStatErasedArea);
1721        strTemp.Format("    Erased area\t\t\t=  %I64u %s\r\n", uTemp, strUnit);
1722        rd.m_strStatistics += strTemp;
1723        // cluster tips
1724        setValueAndUnit(context->m_uStatTips);
1725        strTemp.Format("    Cluster tips\t\t\t=  %I64u %s\r\n", uTemp, strUnit);
1726        rd.m_strStatistics += strTemp;
1727        // written
1728        setValueAndUnit(context->m_uStatWiped);
1729        strTemp.Format("\r\n    Data written\t\t\t=  %I64u %s\r\n", uTemp, strUnit);
1730        rd.m_strStatistics += strTemp;
1731        // time
1732        dTime = (double)context->m_uStatTime / 1000.0f;
1733        strTemp.Format("    Write time\t\t\t=  %.2f %s", dTime, "s");
1734        rd.m_strStatistics += strTemp;
1735        // speed
1736        if (dTime > 0.0) {
1737            strTemp.Format("\r\n    Write speed\t\t\t=  %I64u %s", (E_UINT64)
1738                ((((E_INT64)context->m_uStatWiped / dTime) + 512.0f) / 1024.0f), "kB/s");
1739            rd.m_strStatistics += strTemp;
1740        }
1741
1742        uSize = context->m_saError.GetSize();
1743        for (uIndex = 0; uIndex < uSize; uIndex++) {
1744            strTemp.Format("Error: %s", context->m_saError[uIndex]);
1745            straFailures.Add(strTemp);
1746        }
1747
1748        uSize = context->m_saFailed.GetSize();
1749        for (uIndex = 0; uIndex < uSize; uIndex++) {
1750            strTemp.Format("Failed: %s", context->m_saFailed[uIndex]);
1751            straFailures.Add(strTemp);
1752        }
1753
1754        rd.m_pstraErrorArray = &straFailures;
1755
1756        rd.DoModal();
1757    } catch (...) {
1758        ASSERT(0);
1759        result = ERASER_ERROR_EXCEPTION;
1760    }
1761
1762    wndParent.Detach();
1763    return result;
1764}
1765
1766
1767// Display library options
1768//
1769ERASER_EXPORT
1770eraserShowOptions(E_IN HWND param1, E_IN ERASER_OPTIONS_PAGE param2)
1771{
1772    AFX_MANAGE_STATE(AfxGetStaticModuleState());
1773    eraserTraceBase("eraserShowOptions\n");
1774    if (!eraserIsLibraryInit()) {
1775        return ERASER_ERROR_INIT;
1776    } else if (!IsWindow(param1)) {
1777        return ERASER_ERROR_PARAM1;
1778    }
1779
1780    E_UINT16 uActive;
1781    if (param2 == ERASER_PAGE_DRIVE) {
1782        uActive = 1;
1783    } else if (param2 == ERASER_PAGE_FILES) {
1784        uActive = 0;
1785    } else {
1786        return ERASER_ERROR_PARAM2;
1787    }
1788
1789    ERASER_RESULT result = ERASER_OK;
1790
1791    CWnd wndParent;
1792    wndParent.Attach(param1);
1793
1794    try {
1795       
1796        COptionsDlg dlg(&wndParent);
1797        dlg.SetActivePage(uActive);
1798
1799        if (!loadLibrarySettings(&dlg.m_lsSettings))
1800            setLibraryDefaults(&dlg.m_lsSettings);
1801
1802        AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
1803        if (dlg.DoModal() == IDOK)
1804            saveLibrarySettings(&dlg.m_lsSettings);
1805    } catch (...) {
1806        ASSERT(0);
1807        result = ERASER_ERROR_EXCEPTION;
1808    }
1809
1810    wndParent.Detach();
1811    return result;
1812}
1813
1814
1815// File / directory deletion
1816//
1817ERASER_EXPORT
1818eraserRemoveFile(E_IN LPVOID param1, E_IN E_UINT16 param2)
1819{
1820    AFX_MANAGE_STATE(AfxGetStaticModuleState());
1821    eraserTraceBase("eraserRemoveFile\n");
1822    if (!eraserIsLibraryInit()) {
1823        return ERASER_ERROR_INIT;
1824    }
1825
1826    LPCTSTR pszFile = (LPCTSTR)param1;
1827    if (!AfxIsValidString(pszFile, param2)) {
1828        return ERASER_ERROR_PARAM1;
1829    }
1830
1831    SetFileAttributes(pszFile, FILE_ATTRIBUTE_NORMAL);
1832    SetFileAttributes(pszFile, FILE_ATTRIBUTE_NOT_CONTENT_INDEXED);
1833
1834    if (isWindowsNT) {
1835        TCHAR szLastFileName[MAX_PATH + 1];
1836
1837        overwriteFileName(pszFile, szLastFileName);
1838        void makeWindowsSystemFile(LPTSTR filename);
1839        makeWindowsSystemFile(szLastFileName);
1840        return truthToResult(DeleteFile(szLastFileName));
1841    }
1842
1843    return truthToResult(DeleteFile(pszFile));
1844}
1845
1846ERASER_EXPORT
1847eraserRemoveFolder(E_IN LPVOID param1, E_IN E_UINT16 param2, E_IN E_UINT8 param3)
1848{
1849    AFX_MANAGE_STATE(AfxGetStaticModuleState());
1850    eraserTraceBase("eraserRemoveFolder\n");
1851    if (!eraserIsLibraryInit()) {
1852        return ERASER_ERROR_INIT;
1853    }
1854
1855    LPCTSTR pszFolder = (LPCTSTR)param1;
1856    if (!AfxIsValidString(pszFolder, param2)) {
1857        return ERASER_ERROR_PARAM1;
1858    }
1859
1860    SetFileAttributes(pszFolder, FILE_ATTRIBUTE_NORMAL);
1861
1862    // recursively delete all subfolders and files !?
1863    if (param3 != ERASER_REMOVE_FOLDERONLY) {
1864        emptyFolder(pszFolder);
1865    }
1866
1867    if (isWindowsNT) {
1868        if (!isFolderEmpty(pszFolder)) {
1869            return ERASER_ERROR;
1870        }
1871
1872        CString strFolder(pszFolder);
1873        TCHAR   szLastFileName[MAX_PATH + 1];
1874
1875        if (strFolder[strFolder.GetLength() - 1] == '\\') {
1876            strFolder = strFolder.Left(strFolder.GetLength() - 1);
1877        }
1878
1879        overwriteFileName((LPCTSTR)strFolder, szLastFileName);
1880        return truthToResult(RemoveDirectory(szLastFileName));
1881    }
1882
1883    return truthToResult(RemoveDirectory(pszFolder));
1884}
1885
1886
1887// Helpers
1888//
1889ERASER_EXPORT
1890eraserGetFreeDiskSpace(E_IN LPVOID param1, E_IN E_UINT16 param2, E_OUT E_PUINT64 param3)
1891{
1892    AFX_MANAGE_STATE(AfxGetStaticModuleState());
1893    eraserTraceBase("eraserGetFreeDiskSpace\n");
1894    if (!eraserIsLibraryInit()) {
1895        return ERASER_ERROR_INIT;
1896    }
1897
1898    LPCTSTR pszDrive = (LPCTSTR)param1;
1899    if (!AfxIsValidString(pszDrive, param2)) {
1900        return ERASER_ERROR_PARAM1;
1901    } else if (!AfxIsValidAddress(param3, sizeof(E_UINT64))) {
1902        return ERASER_ERROR_PARAM3;
1903    } else {
1904        try {
1905            *param3 = 0;
1906        } catch (...) {
1907            return ERASER_ERROR_PARAM3;
1908        }
1909    }
1910
1911    ERASER_RESULT result = ERASER_ERROR;
1912    HINSTANCE hInst = AfxLoadLibrary(ERASER_MODULENAME_KERNEL);
1913
1914    if (hInst != NULL) {
1915        ULARGE_INTEGER FreeBytesAvailableToCaller;
1916        ULARGE_INTEGER TotalNumberOfBytes;
1917        ULARGE_INTEGER TotalNumberOfFreeBytes;
1918
1919        GETDISKFREESPACEEX pGetDiskFreeSpaceEx;
1920
1921        pGetDiskFreeSpaceEx =
1922            (GETDISKFREESPACEEX)(GetProcAddress(hInst, ERASER_FUNCTIONNAME_GETDISKFREESPACEEX));
1923
1924        if (pGetDiskFreeSpaceEx) {
1925            try {
1926                if (pGetDiskFreeSpaceEx(pszDrive, &FreeBytesAvailableToCaller,
1927                        &TotalNumberOfBytes, &TotalNumberOfFreeBytes)) {
1928                    *param3 = TotalNumberOfFreeBytes.QuadPart;
1929                    result = ERASER_OK;
1930                }
1931            } catch (...) {
1932                result = ERASER_ERROR_EXCEPTION;
1933            }
1934        }
1935
1936        AfxFreeLibrary(hInst);
1937    }
1938
1939    if (eraserError(result)) {
1940        E_UINT32 dwSecPerClus;
1941        E_UINT32 dwBytPerSec;
1942        E_UINT32 dwFreeClus;
1943        E_UINT32 dwClus;
1944
1945        try {
1946            if (GetDiskFreeSpace(pszDrive, &dwSecPerClus, &dwBytPerSec,
1947                    &dwFreeClus, &dwClus)) {
1948
1949                *param3 = UInt32x32To64(dwFreeClus, dwSecPerClus * dwBytPerSec);
1950                result = ERASER_OK;
1951            }
1952        } catch (...) {
1953            result = ERASER_ERROR_EXCEPTION;
1954        }
1955    }
1956
1957    return result;
1958}
1959
1960ERASER_EXPORT
1961eraserGetClusterSize(E_IN LPVOID param1, E_IN E_UINT16 param2, E_OUT E_PUINT32 param3)
1962{
1963    AFX_MANAGE_STATE(AfxGetStaticModuleState());
1964    eraserTraceBase("eraserGetClusterSize\n");
1965    if (!eraserIsLibraryInit()) {
1966        return ERASER_ERROR_INIT;
1967    }
1968
1969    LPCTSTR pszDrive = (LPCTSTR)param1;
1970    if (!AfxIsValidString(pszDrive, param2)) {
1971        return ERASER_ERROR_PARAM1;
1972    } else if (!AfxIsValidAddress(param3, sizeof(E_UINT64))) {
1973        return ERASER_ERROR_PARAM3;
1974    } else {
1975        try {
1976            *param3 = 0;
1977        } catch (...) {
1978            return ERASER_ERROR_PARAM3;
1979        }
1980    }
1981
1982    ERASER_RESULT result = ERASER_ERROR;
1983
1984    try {
1985        result = truthToResult(getClusterSize(pszDrive, *param3));
1986    } catch (...) {
1987        result = ERASER_ERROR_EXCEPTION;
1988    }
1989
1990    return result;
1991}
1992
1993ERASER_EXPORT
1994eraserTestEnable(E_IN ERASER_HANDLE param1)
1995{
1996    AFX_MANAGE_STATE(AfxGetStaticModuleState());
1997    eraserTraceBase("eraserTestEnable\n");
1998    if (!eraserIsLibraryInit()) {
1999        return ERASER_ERROR_INIT;
2000    }
2001
2002    CEraserContext *context = 0;
2003    if (eraserError(contextToAddress(param1, &context))) {
2004        return ERASER_ERROR_PARAM1;
2005    } else if (eraserInternalIsRunning(context)) {
2006        return ERASER_ERROR_RUNNING;
2007    } else {
2008        try {
2009            eraserContextAccess(context);
2010            context->m_uTestMode = 1;
2011        } catch (...) {
2012            ASSERT(0);
2013            return ERASER_ERROR_EXCEPTION;
2014        }
2015        return ERASER_OK;
2016    }
2017}
2018
2019ERASER_EXPORT
2020eraserTestContinueProcess(E_IN ERASER_HANDLE param1)
2021{
2022    AFX_MANAGE_STATE(AfxGetStaticModuleState());
2023    eraserTraceBase("eraserTestContinueProcess\n");
2024    if (!eraserIsLibraryInit()) {
2025        return ERASER_ERROR_INIT;
2026    }
2027
2028    CEraserContext *context = 0;
2029    if (eraserError(contextToAddress(param1, &context))) {
2030        return ERASER_ERROR_PARAM1;
2031    } else if (!eraserInternalIsRunning(context)) {
2032        return ERASER_ERROR_NOTRUNNING;
2033    } else {
2034        try {
2035            eraserContextAccess(context);
2036            if (!context->m_uTestMode) {
2037                return ERASER_ERROR_DENIED;
2038            }
2039            context->m_evTestContinue.SetEvent();
2040        } catch (...) {
2041            ASSERT(0);
2042            return ERASER_ERROR_EXCEPTION;
2043        }
2044        return ERASER_OK;
2045    }
2046}
2047
2048
2049UINT
2050eraserThread(LPVOID param1)
2051{
2052    AFX_MANAGE_STATE(AfxGetStaticModuleState());
2053    eraserTraceBase("eraserThread\n");
2054    ASSERT(AfxIsValidAddress(param1, sizeof(CEraserContext)));
2055
2056    // structured exception handling
2057    _set_se_translator(SeTranslator);
2058
2059    // parameters class
2060    CEraserContext *context = (CEraserContext*)param1;
2061
2062    try {
2063        context->m_evThreadKilled.ResetEvent();
2064
2065        // do not start before told
2066        WaitForSingleObject(context->m_evStart, INFINITE);
2067        context->m_evDone.ResetEvent();
2068
2069        // user wants to terminate already !?
2070        if (eraserInternalTerminated(context)) {
2071            eraserEndThread(context, EXIT_FAILURE);
2072        }
2073
2074        // set default progress information
2075        eraserDispDefault(context);
2076
2077        // determine the erasing method
2078        E_UINT8 nMethodID = (context->m_edtDataType == ERASER_DATA_FILES) ?
2079                                context->m_lsSettings.m_nFileMethodID : context->m_lsSettings.m_nUDSMethodID;
2080
2081        // initialize method information to the context
2082        if (bitSet(nMethodID, BUILTIN_METHOD_ID)) {
2083            for (E_UINT8 i = 0; i < nBuiltinMethods; i++) {
2084                if (bmMethods[i].m_nMethodID == nMethodID) {
2085                    // we need a thread local copy of the method structure
2086                    // to prevent problems if the calling application runs
2087                    // multiple threads at the same time
2088                    context->m_mThreadLocalMethod = bmMethods[i];
2089                    context->m_lpmMethod = &context->m_mThreadLocalMethod;
2090
2091                    // restore saved information
2092                    if (nMethodID == RANDOM_METHOD_ID) {
2093                        context->m_lpmMethod->m_nPasses =
2094                            (context->m_edtDataType == ERASER_DATA_FILES) ?
2095                                context->m_lsSettings.m_nFileRandom :
2096                                context->m_lsSettings.m_nUDSRandom;
2097                    }
2098
2099                    break;
2100                }
2101            }
2102        } else if (nMethodID <= MAX_CUSTOM_METHOD_ID) {
2103            // find the custom method
2104            for (E_UINT8 i = 0; i < context->m_lsSettings.m_nCMethods; i++) {
2105                if (context->m_lsSettings.m_lpCMethods[i].m_nMethodID == nMethodID) {
2106                    context->m_lpmMethod = &context->m_lsSettings.m_lpCMethods[i];
2107                    context->m_lpmMethod->m_pwfFunction = wipeFileWithCustom;
2108
2109                    break;
2110                }
2111            }
2112        }
2113
2114        // A Bad Thing(TM)
2115        if (context->m_lpmMethod == 0 || context->m_lpmMethod->m_pwfFunction == 0) {
2116            eraserAddError(context, IDS_ERROR_INTERNAL);
2117            eraserEndThread(context, EXIT_FAILURE);
2118        } else {
2119            // set progress information
2120            eraserSafeAssign(context, context->m_uProgressPasses,
2121                             (E_UINT16)context->m_lpmMethod->m_nPasses);
2122        }
2123
2124        // allocate write buffer used by all wipe functions
2125        context->m_puBuffer = (E_PUINT32)VirtualAlloc(NULL, ERASER_DISK_BUFFER_SIZE,
2126                                                      MEM_COMMIT, PAGE_READWRITE);
2127
2128        if (context->m_puBuffer == NULL) {
2129            eraserAddError(context, IDS_ERROR_MEMORY);
2130            eraserEndThread(context, EXIT_FAILURE);
2131        }
2132
2133        // we'll see about this...
2134        bool bCompleted = true;
2135
2136        if (context->m_edtDataType == ERASER_DATA_FILES) {
2137            // files
2138
2139            // number of files to process
2140            context->m_uProgressWipedFiles = 0;
2141            context->m_uProgressFiles = context->m_saData.GetSize();
2142
2143            if (context->m_uProgressFiles > 0) {
2144                E_UINT32 uLength = 0;
2145                E_INT32 iPosition = -1;
2146                TCHAR szShortPath[_MAX_PATH];
2147                CString strDirectory;
2148                CStringList strlDirectories[26]; // drive A = 0, ..., Z = 25
2149
2150                szShortPath[_MAX_PATH - 1] = 0;
2151
2152                // overwrite files
2153                while (context->m_uProgressWipedFiles < context->m_uProgressFiles) {
2154                    if (eraserInternalTerminated(context)) {
2155                        bCompleted = false;
2156                        break;
2157                    }
2158
2159                    // file to process
2160                    eraserSafeAssign(context, context->m_strData,
2161                        context->m_saData[context->m_uProgressWipedFiles]);
2162
2163                    // partition information
2164                    getPartitionInformation(context, context->m_strData[0]);
2165
2166                    // remember which directories to clear
2167                    if (!isWindowsNT && bitSet(context->m_lsSettings.m_uItems, fileNames)) {
2168                        eraserContextAccess(context);
2169                        iPosition = context->m_strData.ReverseFind('\\');
2170
2171                        if (iPosition > 0) {
2172                            strDirectory = context->m_strData.Left(iPosition);
2173
2174                            if (strDirectory.GetLength() > _MAX_DRIVE) {
2175                                uLength = GetShortPathName(strDirectory, szShortPath, _MAX_PATH - 1);
2176
2177                                if (uLength > 2 && uLength <= _MAX_PATH) {
2178                                    strDirectory.Format("%s\\", (LPCTSTR)&szShortPath[2]);
2179                                    strDirectory.MakeUpper();
2180                                } else {
2181                                    strDirectory.Empty();
2182                                }
2183                            } else {
2184                                // root directory
2185                                strDirectory = "\\";
2186                            }
2187
2188                            iPosition = (E_INT32)(context->m_piCurrent.m_szDrive[0] - 'A');
2189
2190                            if (!strDirectory.IsEmpty() &&
2191                                strlDirectories[iPosition].Find(strDirectory) == NULL) {
2192                                // add to the list of directories to process
2193                                strlDirectories[iPosition].AddHead(strDirectory);
2194                            }
2195                        }
2196                    }
2197
2198                    // wipe the file
2199                    eraserBool(bCompleted, wipeFile(context));
2200
2201                    // next file
2202                    context->m_uProgressWipedFiles++;
2203
2204                    // progress
2205                    eraserSafeAssign(context, context->m_uProgressTotalPercent,
2206                        (E_UINT8)((context->m_uProgressWipedFiles * 100) / context->m_uProgressFiles));
2207                    eraserUpdateNotify(context);
2208                }
2209
2210                // clear file names
2211                if (!isWindowsNT && bitSet(context->m_lsSettings.m_uItems, fileNames)) {
2212                    // no progress
2213                    context->m_uProgressFolders = 0;
2214
2215                    for (E_INT32 i = 0; i < 26; i++) {
2216                        eraserDispFileNames(context);
2217
2218                        // go through partitions we accessed
2219                        if (!strlDirectories[i].IsEmpty()) {
2220                            // partition information
2221                            eraserSafeAssign(context, context->m_strData,
2222                                (TCHAR)('A' + i) + CString(":\\"));
2223
2224                            if (getPartitionInformation(context, context->m_strData[0])) {
2225                                // list of directories to clear
2226                                context->m_pstrlDirectories = &strlDirectories[i];
2227
2228                                eraserBool(bCompleted, wipeFATFileEntries(context,
2229                                        ERASER_MESSAGE_FILENAMES_RETRY) == WFE_SUCCESS);
2230                            } else {
2231                                bCompleted = false;
2232                            }
2233                        }
2234                    }
2235
2236                    context->m_pstrlDirectories = 0;
2237                }
2238            } else {
2239                // no files to wipe !?
2240                eraserAddError(context, IDS_ERROR_NODATA);
2241            }
2242        } else {
2243            // unused space on drive(s)
2244
2245            // number of drives to process
2246            context->m_uProgressWipedDrives = 0;
2247            context->m_uProgressDrives = context->m_saData.GetSize();
2248
2249            if (context->m_uProgressDrives > 0) {
2250                while (context->m_uProgressWipedDrives < context->m_uProgressDrives) {
2251                    if (eraserInternalTerminated(context)) {
2252                        bCompleted = false;
2253                        break;
2254                    }
2255
2256                    // drive to process
2257                    eraserSafeAssign(context, context->m_strData,
2258                        context->m_saData[context->m_uProgressWipedDrives]);
2259
2260                    // partition information
2261                    getPartitionInformation(context, context->m_strData[0]);
2262
2263                    // start progress from the beginning
2264                    context->m_uProgressTaskPercent = 0;
2265                    context->m_uProgressFiles = 0;
2266                    context->m_uProgressFolders = 0;
2267
2268                    // how many separate tasks, for total progress information
2269                    countTotalProgressTasks(context);
2270
2271                    // progress information
2272                    if (bitSet(context->m_lsSettings.m_uItems, diskClusterTips) ||
2273                        bitSet(context->m_lsSettings.m_uItems, diskDirEntries)) {
2274                        if (context->m_piCurrent.m_uCluster > 0) {
2275                            // set display options
2276                            eraserDispSearch(context);
2277                            eraserBeginNotify(context);
2278
2279                            countFilesOnDrive(context, context->m_strData, context->m_uProgressFiles,
2280                                              context->m_uProgressFolders);
2281
2282                            // add entropy to the pool
2283                            randomAddEntropy((E_PUINT8)&context->m_uProgressFiles, sizeof(E_UINT32));
2284                            randomAddEntropy((E_PUINT8)&context->m_uProgressFolders, sizeof(E_UINT32));
2285                        }
2286                    }
2287
2288                    // cluster tips
2289                    if (bitSet(context->m_lsSettings.m_uItems, diskClusterTips)) {
2290                        if (eraserInternalTerminated(context)) {
2291                            bCompleted = false;
2292                        } else {
2293                            if (context->m_uProgressFiles > 0 && context->m_piCurrent.m_uCluster > 0) {
2294                                eraserDispClusterTips(context);
2295                                eraserBool(bCompleted, wipeClusterTips(context));
2296
2297                                // restore drive
2298                                eraserSafeAssign(context, context->m_strData,
2299                                    context->m_saData[context->m_uProgressWipedDrives]);
2300                            }
2301
2302                            // task completed
2303                            increaseTotalProgressPercent(context);
2304                        }
2305                    }
2306
2307                    // free space
2308                    if (bitSet(context->m_lsSettings.m_uItems, diskFreeSpace)) {
2309                        if (eraserInternalTerminated(context)) {
2310                            bCompleted = false;
2311                        } else {
2312                            eraserDispDefault(context);
2313                            eraserBool(bCompleted, wipeFreeSpace(context));
2314
2315                            // task completed
2316                            increaseTotalProgressPercent(context);
2317                        }
2318                    }
2319
2320                    // directory entries
2321                    if (bitSet(context->m_lsSettings.m_uItems, diskDirEntries)) {
2322                        // we'll do this last to remove as much traces as possible
2323                        if (eraserInternalTerminated(context)) {
2324                            bCompleted = false;
2325                        } else {
2326                            if (context->m_piCurrent.m_uCluster > 0) {
2327                                eraserDispDirEntries(context);
2328
2329                                if (isWindowsNT && isFileSystemNTFS(context->m_piCurrent)) {
2330                                    // we'll estimate the progress based on MFT size and number of files
2331                                    eraserBool(bCompleted, wipeNTFSFileEntries(context));
2332                                } else {
2333                                    // once again, need to handle the progress ourselves
2334                                    // but this time it is not necessary to show file names
2335
2336                                    context->m_uProgressFolders++; // add one for the root directory
2337                                    eraserBool(bCompleted, wipeFATFileEntries(context,
2338                                               ERASER_MESSAGE_DIRENTRY_RETRY) == WFE_SUCCESS);
2339                                }
2340                            }
2341
2342                            // no need to call increaseTotalProgressPercent since we have
2343                            // now completed work for this drive
2344                        }
2345                    }
2346
2347                    // next drive
2348                    context->m_uProgressWipedDrives++;
2349
2350                    // progress
2351                    eraserSafeAssign(context, context->m_uProgressTotalPercent,
2352                        (E_UINT8)((context->m_uProgressWipedDrives * 100) / context->m_uProgressDrives));
2353                    eraserUpdateNotify(context);
2354                }
2355            } else {
2356                // nothing to wipe
2357                eraserAddError(context, IDS_ERROR_NODATA);
2358            }
2359        } // unused disk space
2360
2361        // free previously allocated write buffer
2362        if (context->m_puBuffer) {
2363            ZeroMemory(context->m_puBuffer, ERASER_DISK_BUFFER_SIZE);
2364            VirtualFree(context->m_puBuffer, 0, MEM_RELEASE);
2365            context->m_puBuffer = 0;
2366        }
2367
2368        // set done flag if nothing has failed
2369        if (bCompleted &&
2370            context->m_saFailed.GetSize() == 0 && context->m_saError.GetSize() == 0) {
2371            context->m_evDone.SetEvent();
2372        }
2373
2374        // bye.
2375            BOOL res;
2376        if (0 != context->m_dwFinishAction) 
2377        {
2378            if(context->m_dwFinishAction != -1)
2379                res = ExitWindowsEx(context->m_dwFinishAction, SHTDN_REASON_MAJOR_OPERATINGSYSTEM | SHTDN_REASON_FLAG_PLANNED);
2380            else {
2381                res = ::SetSystemPowerState(true, false);
2382            }
2383        }
2384        if (eraserInternalCompleted(context)) {
2385            eraserEndThread(context, EXIT_SUCCESS);
2386        } else {
2387            eraserEndThread(context, EXIT_FAILURE);
2388        }
2389    } catch (CException *e) {
2390        handleException(e, context);
2391
2392        if (context->m_puBuffer) {
2393            try {
2394                ZeroMemory(context->m_puBuffer, ERASER_DISK_BUFFER_SIZE);
2395            } catch (...) {
2396            }
2397
2398            try {
2399                VirtualFree(context->m_puBuffer, 0, MEM_RELEASE);
2400                context->m_puBuffer = 0;
2401            } catch (...) {
2402            }
2403        }
2404
2405        try {
2406            eraserEndThread(context, EXIT_FAILURE);
2407        } catch (...) {
2408        }
2409    } catch (...) {
2410        ASSERT(0);
2411
2412        try {
2413            if (context->m_puBuffer) {
2414                ZeroMemory(context->m_puBuffer, ERASER_DISK_BUFFER_SIZE);
2415                VirtualFree(context->m_puBuffer, 0, MEM_RELEASE);
2416                context->m_puBuffer = 0;
2417            }
2418        } catch (...) {
2419        }
2420
2421        try {
2422            eraserAddError(context, IDS_ERROR_INTERNAL);
2423        } catch (...) {
2424        }
2425
2426        try {
2427            eraserEndThread(context, EXIT_FAILURE);
2428        } catch (...) {
2429        }
2430    }
2431
2432    return EXIT_FAILURE;
2433}
2434
2435void makeWindowsSystemFile(LPTSTR filename) {
2436    try {
2437        static CStringArray systemfiles;
2438        if (!systemfiles.GetCount()) {                                  // enumerate suitable windows\system32 files
2439            TCHAR systemdir[MAX_PATH + 1];
2440            systemdir[0] = 0;
2441            ::GetWindowsDirectory(systemdir, MAX_PATH);
2442            if (!systemdir[0])
2443                return;
2444            ::PathAppend(systemdir, _T("system32"));
2445            TCHAR systemdirfind[MAX_PATH + 1];
2446            _tcscpy(systemdirfind, systemdir);
2447            ::PathAppend(systemdirfind, _T("*.*"));
2448
2449            WIN32_FIND_DATA fd;
2450            HANDLE findfile = ::FindFirstFile(systemdirfind, &fd);
2451            if (!findfile || (findfile == INVALID_HANDLE_VALUE))
2452                return;
2453            do {
2454                if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
2455                    continue;
2456                if (fd.nFileSizeHigh || (fd.nFileSizeLow > 1048576) || !fd.nFileSizeLow)
2457                    continue;                                           // prevent taking too much space
2458                TCHAR filename[MAX_PATH + 1];
2459                _tcscpy(filename, systemdir);
2460                ::PathAppend(filename, fd.cFileName);
2461                systemfiles.Add(filename);
2462            } while (::FindNextFile(findfile, &fd));
2463            ::FindClose(findfile);
2464        }
2465
2466        if (!systemfiles.GetCount())
2467            return;
2468
2469        srand((unsigned int)time(NULL));
2470        for (int retries = 10; retries > 0; retries--) {
2471            CFile file;
2472            TCHAR newfilename[MAX_PATH + 1];
2473            _tcscpy(newfilename, systemfiles[rand() % systemfiles.GetCount()]);
2474            if (!file.Open(newfilename, CFile::modeRead | CFile::typeBinary))
2475                continue;
2476            unsigned int len = file.GetLength();
2477            void *buffer = calloc(1, len);
2478            try {
2479                file.Read(buffer, len);
2480            } catch (CException *e) {
2481                free(buffer);
2482                e->Delete();
2483                continue;
2484            }
2485
2486            TCHAR fullnewfilename[MAX_PATH + 1];
2487            _tcscpy(fullnewfilename, filename);
2488            ::PathRemoveFileSpec(fullnewfilename);
2489            ::PathStripPath(newfilename);
2490            ::PathAppend(fullnewfilename, newfilename);
2491
2492            bool ok = false;
2493            if (::MoveFile(filename, fullnewfilename)) {
2494                _tcscpy(filename, fullnewfilename);
2495                ok = true;
2496            } else {
2497                ::Sleep(50);                                            // Allow for Anti-Virus applications to stop looking at the file
2498                if (::MoveFile(filename, fullnewfilename)) {
2499                    _tcscpy(filename, fullnewfilename);
2500                    ok = true;
2501                }
2502            }
2503
2504            if (ok) {
2505                CFile file;
2506                if (file.Open(fullnewfilename, CFile::modeWrite | CFile::typeBinary)) {
2507                    try {
2508                        file.Write(buffer, len);
2509                    } catch(CException *e) {
2510                        e->Delete();
2511                    }
2512                }
2513                free(buffer);
2514                break;
2515            }
2516
2517            free(buffer);
2518        }
2519    } catch (...) {
2520        ASSERT(0);
2521    }
2522}
Note: See TracBrowser for help on using the repository browser.