source: trunk/EraserDll/Eraser.cpp @ 20

Revision 20, 76.3 KB checked in by lowjoel, 7 years ago (diff)

Garrett's updated code.

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