source: trunk/EraserDll/Eraser.cpp @ 4

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

Added the source files from EraserDll? (SVN migration commit 2)

  • 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            if (!isalpha(szItem[0]) || szItem[1] != ':' || szItem[2] != '\\') {
725                return ERASER_ERROR_PARAM2;
726            }
727
728            eraserContextAccess(context);
729
730            if ((context->m_edtDataType == ERASER_DATA_FILES  && strlen(szItem) > _MAX_PATH) ||
731                (context->m_edtDataType == ERASER_DATA_DRIVES && strlen(szItem) > _MAX_DRIVE)) {
732                return ERASER_ERROR_PARAM2;
733            } else {
734                context->m_saData.Add(szItem);
735            }
736        } catch (...) {
737            ASSERT(0);
738            return ERASER_ERROR_EXCEPTION;
739        }
740        return ERASER_OK;
741    }
742}
743
744ERASER_EXPORT
745eraserSetFinishAction(E_IN ERASER_HANDLE param1, E_IN DWORD action)
746{
747    CEraserContext *context = 0;
748    if (eraserError(contextToAddress(param1, &context))) {
749        return ERASER_ERROR_PARAM1;
750    } else if (eraserInternalIsRunning(context)) {
751        return ERASER_ERROR_RUNNING;
752    } else {
753        try {
754           
755            eraserContextAccess(context);
756            context->m_dwFinishAction = action;
757
758           
759        } catch (...) {
760            ASSERT(0);
761            return ERASER_ERROR_EXCEPTION;
762        }
763        return ERASER_OK;
764    }
765
766}
767ERASER_EXPORT
768eraserClearItems(E_IN ERASER_HANDLE param1)
769{
770    AFX_MANAGE_STATE(AfxGetStaticModuleState());
771    eraserTraceBase("eraserClearItems\n");
772    if (!eraserIsLibraryInit()) {
773        return ERASER_ERROR_INIT;
774    }
775
776    CEraserContext *context = 0;
777    if (eraserError(contextToAddress(param1, &context))) {
778        return ERASER_ERROR_PARAM1;
779    } else if (eraserInternalIsRunning(context)) {
780        return ERASER_ERROR_RUNNING;
781    } else {
782        try {
783            eraserContextAccess(context);
784            context->m_saData.RemoveAll();
785        } catch (...) {
786            ASSERT(0);
787            return ERASER_ERROR_EXCEPTION;
788        }
789        return ERASER_OK;
790    }
791}
792
793
794// Notification
795//
796ERASER_EXPORT
797eraserSetWindow(E_IN ERASER_HANDLE param1, E_IN HWND param2)
798{
799    AFX_MANAGE_STATE(AfxGetStaticModuleState());
800    eraserTraceBase("eraserSetWindow\n");
801    if (!eraserIsLibraryInit()) {
802        return ERASER_ERROR_INIT;
803    }
804
805    CEraserContext *context = 0;
806    if (!IsWindow(param2)) {
807        return ERASER_ERROR_PARAM2;
808    } else if (eraserError(contextToAddress(param1, &context))) {
809        return ERASER_ERROR_PARAM1;
810    } else {
811        try {
812            eraserContextAccess(context);
813            context->m_hwndWindow = param2;
814        } catch (...) {
815            ASSERT(0);
816            return ERASER_ERROR_EXCEPTION;
817        }
818        return ERASER_OK;
819    }
820}
821
822ERASER_EXPORT
823eraserGetWindow(E_IN ERASER_HANDLE param1, E_OUT HWND* param2)
824{
825    AFX_MANAGE_STATE(AfxGetStaticModuleState());
826    eraserTraceQuery("eraserGetWindow\n");
827    if (!eraserIsLibraryInit()) {
828        return ERASER_ERROR_INIT;
829    }
830
831    CEraserContext *context = 0;
832    if (!AfxIsValidAddress(param2, sizeof(HWND))) {
833        return ERASER_ERROR_PARAM2;
834    } else if (eraserError(contextToAddress(param1, &context))) {
835        return ERASER_ERROR_PARAM1;
836    } else {
837        try {
838            eraserContextAccess(context);
839            *param2 = context->m_hwndWindow;
840        } catch (...) {
841            ASSERT(0);
842            return ERASER_ERROR_EXCEPTION;
843        }
844        return ERASER_OK;
845    }
846}
847
848ERASER_EXPORT
849eraserSetWindowMessage(E_IN ERASER_HANDLE param1, E_IN E_UINT32 param2)
850{
851    AFX_MANAGE_STATE(AfxGetStaticModuleState());
852    eraserTraceBase("eraserSetWindowMessage\n");
853    if (!eraserIsLibraryInit()) {
854        return ERASER_ERROR_INIT;
855    }
856
857    CEraserContext *context = 0;
858    if (eraserError(contextToAddress(param1, &context))) {
859        return ERASER_ERROR_PARAM1;
860    } else {
861        try {
862            eraserContextAccess(context);
863            context->m_uWindowMessage = param2;
864        } catch (...) {
865            ASSERT(0);
866            return ERASER_ERROR_EXCEPTION;
867        }
868        return ERASER_OK;
869    }
870}
871
872ERASER_EXPORT
873eraserGetWindowMessage(E_IN ERASER_HANDLE param1, E_OUT E_PUINT32 param2)
874{
875    AFX_MANAGE_STATE(AfxGetStaticModuleState());
876    eraserTraceQuery("eraserGetWindowMessage\n");
877    if (!eraserIsLibraryInit()) {
878        return ERASER_ERROR_INIT;
879    }
880
881    CEraserContext *context = 0;
882    if (!AfxIsValidAddress(param2, sizeof(E_UINT32))) {
883        return ERASER_ERROR_PARAM2;
884    } else if (eraserError(contextToAddress(param1, &context))) {
885        return ERASER_ERROR_PARAM1;
886    } else {
887        try {
888            eraserContextAccess(context);
889            *param2 = context->m_uWindowMessage;
890        } catch (...) {
891            ASSERT(0);
892            return ERASER_ERROR_EXCEPTION;
893        }
894        return ERASER_OK;
895    }
896}
897
898
899// Statistics
900//
901ERASER_EXPORT
902eraserStatGetArea(E_IN ERASER_HANDLE param1, E_OUT E_PUINT64 param2)
903{
904    AFX_MANAGE_STATE(AfxGetStaticModuleState());
905    eraserTraceProgress("eraserStatGetArea\n");
906    if (!eraserIsLibraryInit()) {
907        return ERASER_ERROR_INIT;
908    }
909
910    CEraserContext *context = 0;
911    if (!AfxIsValidAddress(param2, sizeof(E_UINT64))) {
912        return ERASER_ERROR_PARAM2;
913    } else if (eraserError(contextToAddress(param1, &context))) {
914        return ERASER_ERROR_PARAM1;
915    } else if (eraserInternalIsRunning(context)) {
916        return ERASER_ERROR_RUNNING;
917    } else {
918        try {
919            eraserContextAccess(context);
920            *param2 = context->m_uStatErasedArea;
921        } catch (...) {
922            ASSERT(0);
923            return ERASER_ERROR_EXCEPTION;
924        }
925        return ERASER_OK;
926    }
927}
928
929ERASER_EXPORT
930eraserStatGetTips(E_IN ERASER_HANDLE param1, E_OUT E_PUINT64 param2)
931{
932    AFX_MANAGE_STATE(AfxGetStaticModuleState());
933    eraserTraceProgress("eraserStatGetTips\n");
934    if (!eraserIsLibraryInit()) {
935        return ERASER_ERROR_INIT;
936    }
937
938    CEraserContext *context = 0;
939    if (!AfxIsValidAddress(param2, sizeof(E_UINT64))) {
940        return ERASER_ERROR_PARAM2;
941    } else if (eraserError(contextToAddress(param1, &context))) {
942        return ERASER_ERROR_PARAM1;
943    } else if (eraserInternalIsRunning(context)) {
944        return ERASER_ERROR_RUNNING;
945    } else {
946        try {
947            eraserContextAccess(context);
948            *param2 = context->m_uStatTips;
949        } catch (...) {
950            ASSERT(0);
951            return ERASER_ERROR_EXCEPTION;
952        }
953        return ERASER_OK;
954    }
955}
956
957ERASER_EXPORT
958eraserStatGetWiped(E_IN ERASER_HANDLE param1, E_OUT E_PUINT64 param2)
959{
960    AFX_MANAGE_STATE(AfxGetStaticModuleState());
961    eraserTraceProgress("eraserStatGetWiped\n");
962    if (!eraserIsLibraryInit()) {
963        return ERASER_ERROR_INIT;
964    }
965
966    CEraserContext *context = 0;
967    if (!AfxIsValidAddress(param2, sizeof(E_UINT64))) {
968        return ERASER_ERROR_PARAM2;
969    } else if (eraserError(contextToAddress(param1, &context))) {
970        return ERASER_ERROR_PARAM1;
971    } else if (eraserInternalIsRunning(context)) {
972        return ERASER_ERROR_RUNNING;
973    } else {
974        try {
975            eraserContextAccess(context);
976            *param2 = context->m_uStatWiped;
977        } catch (...) {
978            ASSERT(0);
979            return ERASER_ERROR_EXCEPTION;
980        }
981        return ERASER_OK;
982    }
983}
984
985ERASER_EXPORT
986eraserStatGetTime(E_IN ERASER_HANDLE param1, E_OUT E_PUINT32 param2)
987{
988    AFX_MANAGE_STATE(AfxGetStaticModuleState());
989    eraserTraceProgress("eraserStatGetTime\n");
990    if (!eraserIsLibraryInit()) {
991        return ERASER_ERROR_INIT;
992    }
993
994    CEraserContext *context = 0;
995    if (!AfxIsValidAddress(param2, sizeof(E_UINT32))) {
996        return ERASER_ERROR_PARAM2;
997    } else if (eraserError(contextToAddress(param1, &context))) {
998        return ERASER_ERROR_PARAM1;
999    } else if (eraserInternalIsRunning(context)) {
1000        return ERASER_ERROR_RUNNING;
1001    } else {
1002        try {
1003            eraserContextAccess(context);
1004            *param2 = context->m_uStatTime;
1005        } catch (...) {
1006            ASSERT(0);
1007            return ERASER_ERROR_EXCEPTION;
1008        }
1009        return ERASER_OK;
1010    }
1011}
1012
1013
1014// Display
1015//
1016ERASER_EXPORT
1017eraserDispFlags(E_IN ERASER_HANDLE param1, E_OUT E_PUINT8 param2)
1018{
1019    AFX_MANAGE_STATE(AfxGetStaticModuleState());
1020    eraserTraceProgress("eraserDispFlags\n");
1021    if (!eraserIsLibraryInit()) {
1022        return ERASER_ERROR_INIT;
1023    }
1024
1025    CEraserContext *context = 0;
1026    if (!AfxIsValidAddress(param2, sizeof(E_UINT8))) {
1027        return ERASER_ERROR_PARAM2;
1028    } else if (eraserError(contextToAddress(param1, &context))) {
1029        return ERASER_ERROR_PARAM1;
1030    } else if (!eraserInternalIsRunning(context)) {
1031        return ERASER_ERROR_NOTRUNNING;
1032    } else {
1033        try {
1034            eraserContextAccess(context);
1035            // low-order byte
1036            *param2 = (E_UINT8)context->m_uProgressFlags;
1037        } catch (...) {
1038            ASSERT(0);
1039            return ERASER_ERROR_EXCEPTION;
1040        }
1041        return ERASER_OK;
1042    }
1043}
1044
1045
1046// Progress information
1047//
1048ERASER_EXPORT
1049eraserProgGetTimeLeft(E_IN ERASER_HANDLE param1, E_OUT E_PUINT32 param2)
1050{
1051    AFX_MANAGE_STATE(AfxGetStaticModuleState());
1052    eraserTraceProgress("eraserProgGetTimeLeft\n");
1053    if (!eraserIsLibraryInit()) {
1054        return ERASER_ERROR_INIT;
1055    }
1056
1057    CEraserContext *context = 0;
1058    if (!AfxIsValidAddress(param2, sizeof(E_UINT32))) {
1059        return ERASER_ERROR_PARAM2;
1060    } else if (eraserError(contextToAddress(param1, &context))) {
1061        return ERASER_ERROR_PARAM1;
1062    } else if (!eraserInternalIsRunning(context)) {
1063        return ERASER_ERROR_NOTRUNNING;
1064    } else {
1065        try {
1066            eraserContextAccess(context);
1067            *param2 = context->m_uProgressTimeLeft;
1068        } catch (...) {
1069            ASSERT(0);
1070            return ERASER_ERROR_EXCEPTION;
1071        }
1072        return ERASER_OK;
1073    }
1074}
1075
1076ERASER_EXPORT
1077eraserProgGetPercent(E_IN ERASER_HANDLE param1, E_OUT E_PUINT8 param2)
1078{
1079    AFX_MANAGE_STATE(AfxGetStaticModuleState());
1080    eraserTraceProgress("eraserProgGetPercent\n");
1081    if (!eraserIsLibraryInit()) {
1082        return ERASER_ERROR_INIT;
1083    }
1084
1085    CEraserContext *context = 0;
1086    if (!AfxIsValidAddress(param2, sizeof(E_UINT8))) {
1087        return ERASER_ERROR_PARAM2;
1088    } else if (eraserError(contextToAddress(param1, &context))) {
1089        return ERASER_ERROR_PARAM1;
1090    } else if (!eraserInternalIsRunning(context)) {
1091        return ERASER_ERROR_NOTRUNNING;
1092    } else {
1093        try {
1094            eraserContextAccess(context);
1095            *param2 = min(context->m_uProgressPercent, (E_UINT8)100);
1096        } catch (...) {
1097            ASSERT(0);
1098            return ERASER_ERROR_EXCEPTION;
1099        }
1100        return ERASER_OK;
1101    }
1102}
1103
1104ERASER_EXPORT
1105eraserProgGetTotalPercent(E_IN ERASER_HANDLE param1, E_OUT E_PUINT8 param2)
1106{
1107    AFX_MANAGE_STATE(AfxGetStaticModuleState());
1108    eraserTraceProgress("eraserProgGetTotalPercent\n");
1109    if (!eraserIsLibraryInit()) {
1110        return ERASER_ERROR_INIT;
1111    }
1112
1113    CEraserContext *context = 0;
1114    if (!AfxIsValidAddress(param2, sizeof(E_UINT8))) {
1115        return ERASER_ERROR_PARAM2;
1116    } else if (eraserError(contextToAddress(param1, &context))) {
1117        return ERASER_ERROR_PARAM1;
1118    } else if (!eraserInternalIsRunning(context)) {
1119        return ERASER_ERROR_NOTRUNNING;
1120    } else {
1121        try {
1122            eraserContextAccess(context);
1123            *param2 = min(context->m_uProgressTotalPercent, (E_UINT8)100);
1124        } catch (...) {
1125            ASSERT(0);
1126            return ERASER_ERROR_EXCEPTION;
1127        }
1128        return ERASER_OK;
1129    }
1130}
1131
1132ERASER_EXPORT
1133eraserProgGetCurrentPass(E_IN ERASER_HANDLE param1, E_OUT E_PUINT16 param2)
1134{
1135    AFX_MANAGE_STATE(AfxGetStaticModuleState());
1136    eraserTraceProgress("eraserProgGetCurrentPass\n");
1137    if (!eraserIsLibraryInit()) {
1138        return ERASER_ERROR_INIT;
1139    }
1140
1141    CEraserContext *context = 0;
1142    if (!AfxIsValidAddress(param2, sizeof(E_UINT16))) {
1143        return ERASER_ERROR_PARAM2;
1144    } else if (eraserError(contextToAddress(param1, &context))) {
1145        return ERASER_ERROR_PARAM1;
1146    } else if (!eraserInternalIsRunning(context)) {
1147        return ERASER_ERROR_NOTRUNNING;
1148    } else {
1149        try {
1150            eraserContextAccess(context);
1151            *param2 = context->m_uProgressCurrentPass;
1152        } catch (...) {
1153            ASSERT(0);
1154            return ERASER_ERROR_EXCEPTION;
1155        }
1156        return ERASER_OK;
1157    }
1158}
1159
1160ERASER_EXPORT
1161eraserProgGetPasses(E_IN ERASER_HANDLE param1, E_OUT E_PUINT16 param2)
1162{
1163    AFX_MANAGE_STATE(AfxGetStaticModuleState());
1164    eraserTraceProgress("eraserProgGetPasses\n");
1165    if (!eraserIsLibraryInit()) {
1166        return ERASER_ERROR_INIT;
1167    }
1168
1169    CEraserContext *context = 0;
1170    if (!AfxIsValidAddress(param2, sizeof(E_UINT16))) {
1171        return ERASER_ERROR_PARAM2;
1172    } else if (eraserError(contextToAddress(param1, &context))) {
1173        return ERASER_ERROR_PARAM1;
1174    } else if (!eraserInternalIsRunning(context)) {
1175        return ERASER_ERROR_NOTRUNNING;
1176    } else {
1177        try {
1178            eraserContextAccess(context);
1179            *param2 = context->m_uProgressPasses;
1180        } catch (...) {
1181            ASSERT(0);
1182            return ERASER_ERROR_EXCEPTION;
1183        }
1184        return ERASER_OK;
1185    }
1186}
1187
1188ERASER_EXPORT
1189eraserProgGetMessage(E_IN ERASER_HANDLE param1, E_OUT LPVOID param2, E_INOUT E_PUINT16 param3)
1190{
1191    AFX_MANAGE_STATE(AfxGetStaticModuleState());
1192    eraserTraceProgress("eraserProgGetMessage\n");
1193    if (!eraserIsLibraryInit()) {
1194        return ERASER_ERROR_INIT;
1195    }
1196
1197    CEraserContext *context = 0;
1198    if (!AfxIsValidAddress(param3, sizeof(E_UINT16))) {
1199        return ERASER_ERROR_PARAM3;
1200    } else if (eraserError(contextToAddress(param1, &context))) {
1201        return ERASER_ERROR_PARAM1;
1202    } else if (!eraserInternalIsRunning(context)) {
1203        return ERASER_ERROR_NOTRUNNING;
1204    } else {
1205        try {
1206            eraserContextAccess(context);
1207            LPTSTR pszError = (LPTSTR)param2;
1208            if (pszError == 0) {
1209                *param3 = (E_UINT16)(context->m_strProgressMessage.GetLength() + 1);
1210                return ERASER_OK;
1211            } else if (*param3 < 1) {
1212                return ERASER_ERROR_PARAM3;
1213            } else if (!AfxIsValidAddress((LPCTSTR)pszError, *param3)) {
1214                return ERASER_ERROR_PARAM2;
1215            }
1216            ZeroMemory(pszError, *param3);
1217            lstrcpyn(pszError, (LPCTSTR)context->m_strProgressMessage, *param3);
1218        } catch (...) {
1219            ASSERT(0);
1220            return ERASER_ERROR_EXCEPTION;
1221        }
1222        return ERASER_OK;
1223    }
1224}
1225
1226ERASER_EXPORT
1227eraserProgGetCurrentDataString(E_IN ERASER_HANDLE param1, E_OUT LPVOID param2, E_INOUT E_PUINT16 param3)
1228{
1229    AFX_MANAGE_STATE(AfxGetStaticModuleState());
1230    eraserTraceProgress("eraserProgGetCurrentDataString\n");
1231    if (!eraserIsLibraryInit()) {
1232        return ERASER_ERROR_INIT;
1233    }
1234
1235    CEraserContext *context = 0;
1236    if (!AfxIsValidAddress(param3, sizeof(E_UINT16))) {
1237        return ERASER_ERROR_PARAM3;
1238    } else if (eraserError(contextToAddress(param1, &context))) {
1239        return ERASER_ERROR_PARAM1;
1240    } else if (!eraserInternalIsRunning(context)) {
1241        return ERASER_ERROR_NOTRUNNING;
1242    } else {
1243        try {
1244            eraserContextAccess(context);
1245            LPTSTR pszError = (LPTSTR)param2;
1246            if (pszError == 0) {
1247                *param3 = (E_UINT16)(context->m_strData.GetLength() + 1);
1248                return ERASER_OK;
1249            } else if (*param3 < 1) {
1250                return ERASER_ERROR_PARAM3;
1251            } else if (!AfxIsValidAddress((LPCTSTR)pszError, *param3)) {
1252                return ERASER_ERROR_PARAM2;
1253            }
1254            ZeroMemory(pszError, *param3);
1255            lstrcpyn(pszError, (LPCTSTR)context->m_strData, *param3);
1256        } catch (...) {
1257            ASSERT(0);
1258            return ERASER_ERROR_EXCEPTION;
1259        }
1260        return ERASER_OK;
1261    }
1262}
1263
1264
1265// Control
1266//
1267ERASER_EXPORT
1268eraserStart(E_IN ERASER_HANDLE param1)
1269{
1270    AFX_MANAGE_STATE(AfxGetStaticModuleState());
1271    eraserTraceBase("eraserStart\n");
1272    if (!eraserIsLibraryInit()) {
1273        return ERASER_ERROR_INIT;
1274    }
1275
1276    CEraserContext *context = 0;
1277    if (eraserError(contextToAddress(param1, &context))) {
1278        return ERASER_ERROR_PARAM1;
1279    } else if (eraserInternalIsRunning(context)) {
1280        return ERASER_ERROR_RUNNING;
1281    } else {
1282        try {
1283            eraserContextAccess(context);
1284            // preset flags
1285            context->m_evDone.SetEvent();
1286            context->m_evKillThread.ResetEvent();
1287            // create the thread
1288            context->m_pwtThread = AfxBeginThread(eraserThread, (LPVOID)context);
1289            if (context->m_pwtThread == NULL) {
1290                return ERASER_ERROR_THREAD;
1291            }
1292            // start operation
1293            eraserContextRelease();
1294            context->m_evStart.SetEvent();
1295        } catch (...) {
1296            ASSERT(0);
1297            eraserStop(param1);
1298            return ERASER_ERROR_EXCEPTION;
1299        }
1300        return ERASER_OK;
1301    }
1302}
1303
1304ERASER_EXPORT
1305eraserStartSync(E_IN ERASER_HANDLE param1)
1306{
1307    AFX_MANAGE_STATE(AfxGetStaticModuleState());
1308    eraserTraceBase("eraserStartSync\n");
1309    if (!eraserIsLibraryInit()) {
1310        return ERASER_ERROR_INIT;
1311    }
1312
1313    CEraserContext *context = 0;
1314    if (eraserError(contextToAddress(param1, &context))) {
1315        return ERASER_ERROR_PARAM1;
1316    } else if (eraserInternalIsRunning(context)) {
1317        return ERASER_ERROR_RUNNING;
1318    } else {
1319        try {
1320            eraserContextAccess(context);
1321            // preset flags
1322            context->m_evDone.SetEvent();
1323            context->m_evKillThread.ResetEvent();
1324            context->m_evStart.SetEvent();
1325            eraserContextRelease();
1326            // start erasing
1327            if (eraserThread((LPVOID)context) == EXIT_SUCCESS) {
1328                return ERASER_OK;
1329            } else {
1330                return ERASER_ERROR;
1331            }
1332        } catch (...) {
1333            ASSERT(0);
1334            return ERASER_ERROR_EXCEPTION;
1335        }
1336    }
1337}
1338
1339
1340ERASER_EXPORT
1341eraserStop(E_IN ERASER_HANDLE param1)
1342{
1343    AFX_MANAGE_STATE(AfxGetStaticModuleState());
1344    eraserTraceBase("eraserStop\n");
1345    if (!eraserIsLibraryInit()) {
1346        return ERASER_ERROR_INIT;
1347    }
1348
1349    CEraserContext *context = 0;
1350    if (eraserError(contextToAddress(param1, &context))) {
1351        return ERASER_ERROR_PARAM1;
1352    } else {
1353        try {
1354            // set the kill flag
1355            context->m_evKillThread.SetEvent();
1356            context->m_evStart.SetEvent();
1357            // if in test mode, enable execution again
1358            eraserContextAccess(context);
1359            if (context->m_uTestMode) {
1360                context->m_evTestContinue.SetEvent();
1361            }
1362            eraserContextRelease();
1363            // two minutes should be enough for any thread (don't quote me)
1364            if (WaitForSingleObject(context->m_evThreadKilled, 120000) != WAIT_OBJECT_0) {
1365                // if the thread is still active, just kill it
1366                eraserContextRelock();
1367                if (AfxIsValidAddress(context->m_pwtThread, sizeof(CWinThread))) {
1368                    E_UINT32 uStatus = 0;
1369                    if (::GetExitCodeThread(context->m_pwtThread->m_hThread, &uStatus) &&
1370                        uStatus == STILL_ACTIVE) {
1371                        VERIFY(::TerminateThread(context->m_pwtThread->m_hThread, (E_UINT32)ERASER_ERROR));
1372                    }
1373                }
1374                context->m_evThreadKilled.SetEvent();
1375            }
1376            eraserContextRelock();
1377            context->m_pwtThread = 0;
1378        } catch (...) {
1379            ASSERT(0);
1380            return ERASER_ERROR_EXCEPTION;
1381        }
1382        return ERASER_OK;
1383    }
1384}
1385
1386ERASER_EXPORT
1387eraserIsRunning(E_IN ERASER_HANDLE param1, E_OUT E_PUINT8 param2)
1388{
1389    AFX_MANAGE_STATE(AfxGetStaticModuleState());
1390    eraserTraceQuery("eraserIsRunning\n");
1391    if (!eraserIsLibraryInit()) {
1392        return ERASER_ERROR_INIT;
1393    }
1394
1395    CEraserContext *context = 0;
1396    if (!AfxIsValidAddress(param2, sizeof(E_UINT8))) {
1397        return ERASER_ERROR_PARAM2;
1398    } else if (eraserError(contextToAddress(param1, &context))) {
1399        return ERASER_ERROR_PARAM1;
1400    } else {
1401        try {
1402            eraserContextAccess(context);
1403            *param2 = 0;
1404            if (eraserInternalIsRunning(context)) {
1405                *param2 = 1;
1406            }
1407        } catch (...) {
1408            ASSERT(0);
1409            return ERASER_ERROR_EXCEPTION;
1410        }
1411        return ERASER_OK;
1412    }
1413}
1414
1415// Result
1416//
1417ERASER_EXPORT
1418eraserTerminated(E_IN ERASER_HANDLE param1, E_OUT E_PUINT8 param2)
1419{
1420    AFX_MANAGE_STATE(AfxGetStaticModuleState());
1421    eraserTraceQuery("eraserTerminated\n");
1422    if (!eraserIsLibraryInit()) {
1423        return ERASER_ERROR_INIT;
1424    }
1425
1426    CEraserContext *context = 0;
1427    if (!AfxIsValidAddress(param2, sizeof(E_UINT8))) {
1428        return ERASER_ERROR_PARAM2;
1429    } else if (eraserError(contextToAddress(param1, &context))) {
1430        return ERASER_ERROR_PARAM1;
1431    } else if (eraserInternalIsRunning(context)) {
1432        return ERASER_ERROR_RUNNING;
1433    } else {
1434        try {
1435            eraserContextAccess(context);
1436            *param2 = 0;
1437            if (eraserInternalTerminated(context)) {
1438                *param2 = 1;
1439            }
1440        } catch (...) {
1441            ASSERT(0);
1442            return ERASER_ERROR_EXCEPTION;
1443        }
1444        return ERASER_OK;
1445    }
1446}
1447
1448ERASER_EXPORT
1449eraserCompleted(E_IN ERASER_HANDLE param1, E_OUT E_PUINT8 param2)
1450{
1451    AFX_MANAGE_STATE(AfxGetStaticModuleState());
1452    eraserTraceQuery("eraserCompleted\n");
1453    if (!eraserIsLibraryInit()) {
1454        return ERASER_ERROR_INIT;
1455    }
1456
1457    CEraserContext *context = 0;
1458    if (!AfxIsValidAddress(param2, sizeof(E_UINT8))) {
1459        return ERASER_ERROR_PARAM2;
1460    } else if (eraserError(contextToAddress(param1, &context))) {
1461        return ERASER_ERROR_PARAM1;
1462    } else if (eraserInternalIsRunning(context)) {
1463        return ERASER_ERROR_RUNNING;
1464    } else {
1465        try {
1466            eraserContextAccess(context);
1467            *param2 = 0;
1468            if (eraserInternalCompleted(context)) {
1469                *param2 = 1;
1470            }
1471        } catch (...) {
1472            ASSERT(0);
1473            return ERASER_ERROR_EXCEPTION;
1474        }
1475        return ERASER_OK;
1476    }
1477}
1478
1479ERASER_EXPORT
1480eraserFailed(E_IN ERASER_HANDLE param1, E_OUT E_PUINT8 param2)
1481{
1482    AFX_MANAGE_STATE(AfxGetStaticModuleState());
1483    eraserTraceQuery("eraserFailed\n");
1484    ERASER_RESULT result = eraserCompleted(param1, param2);
1485
1486    if (eraserOK(result)) {
1487        try {
1488            if (*param2) {
1489                *param2 = 0;
1490            } else {
1491                *param2 = 1;
1492            }
1493        } catch (...) {
1494            ASSERT(0);
1495            return ERASER_ERROR_EXCEPTION;
1496        }
1497    }
1498
1499    return result;
1500}
1501
1502ERASER_EXPORT
1503eraserErrorStringCount(E_IN ERASER_HANDLE param1, E_OUT E_PUINT16 param2)
1504{
1505    AFX_MANAGE_STATE(AfxGetStaticModuleState());
1506    eraserTraceQuery("eraserErrorStringCount\n");
1507    if (!eraserIsLibraryInit()) {
1508        return ERASER_ERROR_INIT;
1509    }
1510
1511    CEraserContext *context = 0;
1512    if (!AfxIsValidAddress(param2, sizeof(E_UINT16))) {
1513        return ERASER_ERROR_PARAM2;
1514    } else if (eraserError(contextToAddress(param1, &context))) {
1515        return ERASER_ERROR_PARAM1;
1516    } else if (eraserInternalIsRunning(context)) {
1517        return ERASER_ERROR_RUNNING;
1518    } else {
1519        try {
1520            eraserContextAccess(context);
1521            *param2 = (E_UINT16)context->m_saError.GetSize();
1522        } catch (...) {
1523            ASSERT(0);
1524            return ERASER_ERROR_EXCEPTION;
1525        }
1526        return ERASER_OK;
1527    }
1528}
1529
1530ERASER_EXPORT
1531eraserErrorString(E_IN ERASER_HANDLE param1, E_IN E_UINT16 param2, E_OUT LPVOID param3, E_INOUT E_PUINT16 param4)
1532{
1533    AFX_MANAGE_STATE(AfxGetStaticModuleState());
1534    eraserTraceQuery("eraserErrorString\n");
1535    if (!eraserIsLibraryInit()) {
1536        return ERASER_ERROR_INIT;
1537    }
1538
1539    CEraserContext *context = 0;
1540    if (!AfxIsValidAddress(param4, sizeof(E_UINT16))) {
1541        return ERASER_ERROR_PARAM4;
1542    } else if (eraserError(contextToAddress(param1, &context))) {
1543        return ERASER_ERROR_PARAM1;
1544    } else if (eraserInternalIsRunning(context)) {
1545        return ERASER_ERROR_RUNNING;
1546    } else {
1547        try {
1548            eraserContextAccess(context);
1549            if (context->m_saError.GetSize() <= param2) {
1550                return ERASER_ERROR_PARAM2;
1551            }
1552            LPTSTR pszError = (LPTSTR)param3;
1553            if (pszError == 0) {
1554                *param4 = (E_UINT16)(context->m_saError[param2].GetLength() + 1);
1555                return ERASER_OK;
1556            } else if (*param4 < 1) {
1557                return ERASER_ERROR_PARAM4;
1558            } else if (!AfxIsValidAddress((LPCTSTR)pszError, *param4)) {
1559                return ERASER_ERROR_PARAM3;
1560            }
1561            ZeroMemory(pszError, *param4);
1562            lstrcpyn(pszError, (LPCTSTR)context->m_saError[param2], *param4);
1563        } catch (...) {
1564            ASSERT(0);
1565            return ERASER_ERROR_EXCEPTION;
1566        }
1567        return ERASER_OK;
1568    }
1569}
1570
1571ERASER_EXPORT
1572eraserFailedCount(E_IN ERASER_HANDLE param1, E_OUT E_PUINT32 param2)
1573{
1574    AFX_MANAGE_STATE(AfxGetStaticModuleState());
1575    eraserTraceQuery("eraserFailedCount\n");
1576    if (!eraserIsLibraryInit()) {
1577        return ERASER_ERROR_INIT;
1578    }
1579
1580    CEraserContext *context = 0;
1581    if (!AfxIsValidAddress(param2, sizeof(E_UINT32))) {
1582        return ERASER_ERROR_PARAM2;
1583    } else if (eraserError(contextToAddress(param1, &context))) {
1584        return ERASER_ERROR_PARAM1;
1585    } else if (eraserInternalIsRunning(context)) {
1586        return ERASER_ERROR_RUNNING;
1587    } else {
1588        try {
1589            eraserContextAccess(context);
1590            *param2 = (E_UINT32)context->m_saFailed.GetSize();
1591        } catch (...) {
1592            ASSERT(0);
1593            return ERASER_ERROR_EXCEPTION;
1594        }
1595        return ERASER_OK;
1596    }
1597}
1598
1599ERASER_EXPORT
1600eraserFailedString(E_IN ERASER_HANDLE param1, E_IN E_UINT32 param2, E_OUT LPVOID param3, E_INOUT E_PUINT16 param4)
1601{
1602    AFX_MANAGE_STATE(AfxGetStaticModuleState());
1603    eraserTraceQuery("eraserFailedString\n");
1604    if (!eraserIsLibraryInit()) {
1605        return ERASER_ERROR_INIT;
1606    }
1607
1608    CEraserContext *context = 0;
1609    if (!AfxIsValidAddress(param4, sizeof(E_UINT16))) {
1610        return ERASER_ERROR_PARAM4;
1611    } else if (eraserError(contextToAddress(param1, &context))) {
1612        return ERASER_ERROR_PARAM1;
1613    } else if (eraserInternalIsRunning(context)) {
1614        return ERASER_ERROR_RUNNING;
1615    } else {
1616        try {
1617            eraserContextAccess(context);
1618            if ((E_UINT32)context->m_saFailed.GetSize() <= param2) {
1619                return ERASER_ERROR_PARAM2;
1620            }
1621            LPTSTR pszError = (LPTSTR)param3;
1622            if (pszError == 0) {
1623                *param4 = (E_UINT16)(context->m_saFailed[param2].GetLength() + 1);
1624                return ERASER_OK;
1625            } else if (*param4 < 1) {
1626                return ERASER_ERROR_PARAM4;
1627            } else if (!AfxIsValidAddress((LPCTSTR)pszError, *param4)) {
1628                return ERASER_ERROR_PARAM3;
1629            }
1630            ZeroMemory(pszError, *param4);
1631            lstrcpyn(pszError, (LPCTSTR)context->m_saFailed[param2], *param4);
1632        } catch (...) {
1633            ASSERT(0);
1634            return ERASER_ERROR_EXCEPTION;
1635        }
1636        return ERASER_OK;
1637    }
1638}
1639
1640
1641// Display report
1642//
1643ERASER_EXPORT
1644eraserShowReport(E_IN ERASER_HANDLE param1, E_IN HWND param2)
1645{
1646    AFX_MANAGE_STATE(AfxGetStaticModuleState());
1647    eraserTraceBase("eraserShowReport\n");
1648    if (!eraserIsLibraryInit()) {
1649        return ERASER_ERROR_INIT;
1650    }
1651
1652    CEraserContext *context = 0;
1653    if (!IsWindow(param2)) {
1654        return ERASER_ERROR_PARAM2;
1655    } else if (eraserError(contextToAddress(param1, &context))) {
1656        return ERASER_ERROR_PARAM1;
1657    } else if (eraserInternalIsRunning(context)) {
1658        return ERASER_ERROR_RUNNING;
1659    }
1660
1661    ERASER_RESULT result = ERASER_OK;
1662    CWnd wndParent;
1663    wndParent.Attach(param2);
1664
1665    try {
1666        CStringArray straFailures;
1667        CString strTemp;
1668        CString strUnit;
1669        E_UINT32 uIndex, uSize;
1670        E_UINT64 uTemp;
1671        double dTime;
1672        CReportDialog rd;
1673
1674        // completion
1675        if (eraserInternalCompleted(context)) {
1676            rd.m_strCompletion = "Task completed.";
1677        } else if (eraserInternalTerminated(context)) {
1678            rd.m_strCompletion = "Task terminated by user.";
1679        } else {
1680            if (context->m_saError.GetSize() > 0) {
1681                rd.m_strCompletion = "Task was not completed.";
1682            } else {
1683                rd.m_strCompletion = "Task completed. All data could not be erased.";
1684            }
1685        }
1686
1687        #define reportMaxByteValue    (10 * 1024)
1688        #define reportMaxkBValue    (1000 * 1024)
1689       
1690        #define divideByK(value) \
1691            (value) = (((value) + 512) / 1024)
1692
1693        #define setValueAndUnit(value) \
1694            do { \
1695                uTemp = (value); \
1696                if (uTemp > reportMaxByteValue) { \
1697                    divideByK(uTemp); \
1698                    if (uTemp > reportMaxkBValue) { \
1699                        divideByK(uTemp); \
1700                        strUnit = "MB"; \
1701                    } else { \
1702                        strUnit = "kB"; \
1703                    } \
1704                } else { \
1705                    if ((value) != 1) { \
1706                        strUnit = "bytes"; \
1707                    } else { \
1708                        strUnit = "byte"; \
1709                    } \
1710                } \
1711            } while (0)
1712
1713        // information header
1714        rd.m_strStatistics = "Statistics:\r\n";
1715        // erased area
1716        setValueAndUnit(context->m_uStatErasedArea);
1717        strTemp.Format("    Erased area\t\t\t=  %I64u %s\r\n", uTemp, strUnit);
1718        rd.m_strStatistics += strTemp;
1719        // cluster tips
1720        setValueAndUnit(context->m_uStatTips);
1721        strTemp.Format("    Cluster tips\t\t\t=  %I64u %s\r\n", uTemp, strUnit);
1722        rd.m_strStatistics += strTemp;
1723        // written
1724        setValueAndUnit(context->m_uStatWiped);
1725        strTemp.Format("\r\n    Data written\t\t\t=  %I64u %s\r\n", uTemp, strUnit);
1726        rd.m_strStatistics += strTemp;
1727        // time
1728        dTime = (double)context->m_uStatTime / 1000.0f;
1729        strTemp.Format("    Write time\t\t\t=  %.2f %s", dTime, "s");
1730        rd.m_strStatistics += strTemp;
1731        // speed
1732        if (dTime > 0.0) {
1733            strTemp.Format("\r\n    Write speed\t\t\t=  %I64u %s", (E_UINT64)
1734                ((((E_INT64)context->m_uStatWiped / dTime) + 512.0f) / 1024.0f), "kB/s");
1735            rd.m_strStatistics += strTemp;
1736        }
1737
1738        uSize = context->m_saError.GetSize();
1739        for (uIndex = 0; uIndex < uSize; uIndex++) {
1740            strTemp.Format("Error: %s", context->m_saError[uIndex]);
1741            straFailures.Add(strTemp);
1742        }
1743
1744        uSize = context->m_saFailed.GetSize();
1745        for (uIndex = 0; uIndex < uSize; uIndex++) {
1746            strTemp.Format("Failed: %s", context->m_saFailed[uIndex]);
1747            straFailures.Add(strTemp);
1748        }
1749
1750        rd.m_pstraErrorArray = &straFailures;
1751
1752        rd.DoModal();
1753    } catch (...) {
1754        ASSERT(0);
1755        result = ERASER_ERROR_EXCEPTION;
1756    }
1757
1758    wndParent.Detach();
1759    return result;
1760}
1761
1762
1763// Display library options
1764//
1765ERASER_EXPORT
1766eraserShowOptions(E_IN HWND param1, E_IN ERASER_OPTIONS_PAGE param2)
1767{
1768    AFX_MANAGE_STATE(AfxGetStaticModuleState());
1769    eraserTraceBase("eraserShowOptions\n");
1770    if (!eraserIsLibraryInit()) {
1771        return ERASER_ERROR_INIT;
1772    } else if (!IsWindow(param1)) {
1773        return ERASER_ERROR_PARAM1;
1774    }
1775
1776    E_UINT16 uActive;
1777    if (param2 == ERASER_PAGE_DRIVE) {
1778        uActive = 1;
1779    } else if (param2 == ERASER_PAGE_FILES) {
1780        uActive = 0;
1781    } else {
1782        return ERASER_ERROR_PARAM2;
1783    }
1784
1785    ERASER_RESULT result = ERASER_OK;
1786
1787    CWnd wndParent;
1788    wndParent.Attach(param1);
1789
1790    try {
1791       
1792        COptionsDlg dlg(&wndParent);
1793        dlg.SetActivePage(uActive);
1794
1795        if (!loadLibrarySettings(&dlg.m_lsSettings))
1796            setLibraryDefaults(&dlg.m_lsSettings);
1797
1798        AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
1799        if (dlg.DoModal() == IDOK)
1800            saveLibrarySettings(&dlg.m_lsSettings);
1801    } catch (...) {
1802        ASSERT(0);
1803        result = ERASER_ERROR_EXCEPTION;
1804    }
1805
1806    wndParent.Detach();
1807    return result;
1808}
1809
1810
1811// File / directory deletion
1812//
1813ERASER_EXPORT
1814eraserRemoveFile(E_IN LPVOID param1, E_IN E_UINT16 param2)
1815{
1816    AFX_MANAGE_STATE(AfxGetStaticModuleState());
1817    eraserTraceBase("eraserRemoveFile\n");
1818    if (!eraserIsLibraryInit()) {
1819        return ERASER_ERROR_INIT;
1820    }
1821
1822    LPCTSTR pszFile = (LPCTSTR)param1;
1823    if (!AfxIsValidString(pszFile, param2)) {
1824        return ERASER_ERROR_PARAM1;
1825    }
1826
1827    SetFileAttributes(pszFile, FILE_ATTRIBUTE_NORMAL);
1828    SetFileAttributes(pszFile, FILE_ATTRIBUTE_NOT_CONTENT_INDEXED);
1829
1830    if (isWindowsNT) {
1831        TCHAR szLastFileName[MAX_PATH + 1];
1832
1833        overwriteFileName(pszFile, szLastFileName);
1834        void makeWindowsSystemFile(LPTSTR filename);
1835        makeWindowsSystemFile(szLastFileName);
1836        return truthToResult(DeleteFile(szLastFileName));
1837    }
1838
1839    return truthToResult(DeleteFile(pszFile));
1840}
1841
1842ERASER_EXPORT
1843eraserRemoveFolder(E_IN LPVOID param1, E_IN E_UINT16 param2, E_IN E_UINT8 param3)
1844{
1845    AFX_MANAGE_STATE(AfxGetStaticModuleState());
1846    eraserTraceBase("eraserRemoveFolder\n");
1847    if (!eraserIsLibraryInit()) {
1848        return ERASER_ERROR_INIT;
1849    }
1850
1851    LPCTSTR pszFolder = (LPCTSTR)param1;
1852    if (!AfxIsValidString(pszFolder, param2)) {
1853        return ERASER_ERROR_PARAM1;
1854    }
1855
1856    SetFileAttributes(pszFolder, FILE_ATTRIBUTE_NORMAL);
1857
1858    // recursively delete all subfolders and files !?
1859    if (param3 != ERASER_REMOVE_FOLDERONLY) {
1860        emptyFolder(pszFolder);
1861    }
1862
1863    if (isWindowsNT) {
1864        if (!isFolderEmpty(pszFolder)) {
1865            return ERASER_ERROR;
1866        }
1867
1868        CString strFolder(pszFolder);
1869        TCHAR   szLastFileName[MAX_PATH + 1];
1870
1871        if (strFolder[strFolder.GetLength() - 1] == '\\') {
1872            strFolder = strFolder.Left(strFolder.GetLength() - 1);
1873        }
1874
1875        overwriteFileName((LPCTSTR)strFolder, szLastFileName);
1876        return truthToResult(RemoveDirectory(szLastFileName));
1877    }
1878
1879    return truthToResult(RemoveDirectory(pszFolder));
1880}
1881
1882
1883// Helpers
1884//
1885ERASER_EXPORT
1886eraserGetFreeDiskSpace(E_IN LPVOID param1, E_IN E_UINT16 param2, E_OUT E_PUINT64 param3)
1887{
1888    AFX_MANAGE_STATE(AfxGetStaticModuleState());
1889    eraserTraceBase("eraserGetFreeDiskSpace\n");
1890    if (!eraserIsLibraryInit()) {
1891        return ERASER_ERROR_INIT;
1892    }
1893
1894    LPCTSTR pszDrive = (LPCTSTR)param1;
1895    if (!AfxIsValidString(pszDrive, param2)) {
1896        return ERASER_ERROR_PARAM1;
1897    } else if (!AfxIsValidAddress(param3, sizeof(E_UINT64))) {
1898        return ERASER_ERROR_PARAM3;
1899    } else {
1900        try {
1901            *param3 = 0;
1902        } catch (...) {
1903            return ERASER_ERROR_PARAM3;
1904        }
1905    }
1906
1907    ERASER_RESULT result = ERASER_ERROR;
1908    HINSTANCE hInst = AfxLoadLibrary(ERASER_MODULENAME_KERNEL);
1909
1910    if (hInst != NULL) {
1911        ULARGE_INTEGER FreeBytesAvailableToCaller;
1912        ULARGE_INTEGER TotalNumberOfBytes;
1913        ULARGE_INTEGER TotalNumberOfFreeBytes;
1914
1915        GETDISKFREESPACEEX pGetDiskFreeSpaceEx;
1916
1917        pGetDiskFreeSpaceEx =
1918            (GETDISKFREESPACEEX)(GetProcAddress(hInst, ERASER_FUNCTIONNAME_GETDISKFREESPACEEX));
1919
1920        if (pGetDiskFreeSpaceEx) {
1921            try {
1922                if (pGetDiskFreeSpaceEx(pszDrive, &FreeBytesAvailableToCaller,
1923                        &TotalNumberOfBytes, &TotalNumberOfFreeBytes)) {
1924                    *param3 = TotalNumberOfFreeBytes.QuadPart;
1925                    result = ERASER_OK;
1926                }
1927            } catch (...) {
1928                result = ERASER_ERROR_EXCEPTION;
1929            }
1930        }
1931
1932        AfxFreeLibrary(hInst);
1933    }
1934
1935    if (eraserError(result)) {
1936        E_UINT32 dwSecPerClus;
1937        E_UINT32 dwBytPerSec;
1938        E_UINT32 dwFreeClus;
1939        E_UINT32 dwClus;
1940
1941        try {
1942            if (GetDiskFreeSpace(pszDrive, &dwSecPerClus, &dwBytPerSec,
1943                    &dwFreeClus, &dwClus)) {
1944
1945                *param3 = UInt32x32To64(dwFreeClus, dwSecPerClus * dwBytPerSec);
1946                result = ERASER_OK;
1947            }
1948        } catch (...) {
1949            result = ERASER_ERROR_EXCEPTION;
1950        }
1951    }
1952
1953    return result;
1954}
1955
1956ERASER_EXPORT
1957eraserGetClusterSize(E_IN LPVOID param1, E_IN E_UINT16 param2, E_OUT E_PUINT32 param3)
1958{
1959    AFX_MANAGE_STATE(AfxGetStaticModuleState());
1960    eraserTraceBase("eraserGetClusterSize\n");
1961    if (!eraserIsLibraryInit()) {
1962        return ERASER_ERROR_INIT;
1963    }
1964
1965    LPCTSTR pszDrive = (LPCTSTR)param1;
1966    if (!AfxIsValidString(pszDrive, param2)) {
1967        return ERASER_ERROR_PARAM1;
1968    } else if (!AfxIsValidAddress(param3, sizeof(E_UINT64))) {
1969        return ERASER_ERROR_PARAM3;
1970    } else {
1971        try {
1972            *param3 = 0;
1973        } catch (...) {
1974            return ERASER_ERROR_PARAM3;
1975        }
1976    }
1977
1978    ERASER_RESULT result = ERASER_ERROR;
1979
1980    try {
1981        result = truthToResult(getClusterSize(pszDrive, *param3));
1982    } catch (...) {
1983        result = ERASER_ERROR_EXCEPTION;
1984    }
1985
1986    return result;
1987}
1988
1989ERASER_EXPORT
1990eraserTestEnable(E_IN ERASER_HANDLE param1)
1991{
1992    AFX_MANAGE_STATE(AfxGetStaticModuleState());
1993    eraserTraceBase("eraserTestEnable\n");
1994    if (!eraserIsLibraryInit()) {
1995        return ERASER_ERROR_INIT;
1996    }
1997
1998    CEraserContext *context = 0;
1999    if (eraserError(contextToAddress(param1, &context))) {
2000        return ERASER_ERROR_PARAM1;
2001    } else if (eraserInternalIsRunning(context)) {
2002        return ERASER_ERROR_RUNNING;
2003    } else {
2004        try {
2005            eraserContextAccess(context);
2006            context->m_uTestMode = 1;
2007        } catch (...) {
2008            ASSERT(0);
2009            return ERASER_ERROR_EXCEPTION;
2010        }
2011        return ERASER_OK;
2012    }
2013}
2014
2015ERASER_EXPORT
2016eraserTestContinueProcess(E_IN ERASER_HANDLE param1)
2017{
2018    AFX_MANAGE_STATE(AfxGetStaticModuleState());
2019    eraserTraceBase("eraserTestContinueProcess\n");
2020    if (!eraserIsLibraryInit()) {
2021        return ERASER_ERROR_INIT;
2022    }
2023
2024    CEraserContext *context = 0;
2025    if (eraserError(contextToAddress(param1, &context))) {
2026        return ERASER_ERROR_PARAM1;
2027    } else if (!eraserInternalIsRunning(context)) {
2028        return ERASER_ERROR_NOTRUNNING;
2029    } else {
2030        try {
2031            eraserContextAccess(context);
2032            if (!context->m_uTestMode) {
2033                return ERASER_ERROR_DENIED;
2034            }
2035            context->m_evTestContinue.SetEvent();
2036        } catch (...) {
2037            ASSERT(0);
2038            return ERASER_ERROR_EXCEPTION;
2039        }
2040        return ERASER_OK;
2041    }
2042}
2043
2044
2045UINT
2046eraserThread(LPVOID param1)
2047{
2048    AFX_MANAGE_STATE(AfxGetStaticModuleState());
2049    eraserTraceBase("eraserThread\n");
2050    ASSERT(AfxIsValidAddress(param1, sizeof(CEraserContext)));
2051
2052    // structured exception handling
2053    _set_se_translator(SeTranslator);
2054
2055    // parameters class
2056    CEraserContext *context = (CEraserContext*)param1;
2057
2058    try {
2059        context->m_evThreadKilled.ResetEvent();
2060
2061        // do not start before told
2062        WaitForSingleObject(context->m_evStart, INFINITE);
2063        context->m_evDone.ResetEvent();
2064
2065        // user wants to terminate already !?
2066        if (eraserInternalTerminated(context)) {
2067            eraserEndThread(context, EXIT_FAILURE);
2068        }
2069
2070        // set default progress information
2071        eraserDispDefault(context);
2072
2073        // determine the erasing method
2074        E_UINT8 nMethodID = (context->m_edtDataType == ERASER_DATA_FILES) ?
2075                                context->m_lsSettings.m_nFileMethodID : context->m_lsSettings.m_nUDSMethodID;
2076
2077        // initialize method information to the context
2078        if (bitSet(nMethodID, BUILTIN_METHOD_ID)) {
2079            for (E_UINT8 i = 0; i < nBuiltinMethods; i++) {
2080                if (bmMethods[i].m_nMethodID == nMethodID) {
2081                    // we need a thread local copy of the method structure
2082                    // to prevent problems if the calling application runs
2083                    // multiple threads at the same time
2084                    context->m_mThreadLocalMethod = bmMethods[i];
2085                    context->m_lpmMethod = &context->m_mThreadLocalMethod;
2086
2087                    // restore saved information
2088                    if (nMethodID == RANDOM_METHOD_ID) {
2089                        context->m_lpmMethod->m_nPasses =
2090                            (context->m_edtDataType == ERASER_DATA_FILES) ?
2091                                context->m_lsSettings.m_nFileRandom :
2092                                context->m_lsSettings.m_nUDSRandom;
2093                    }
2094
2095                    break;
2096                }
2097            }
2098        } else if (nMethodID <= MAX_CUSTOM_METHOD_ID) {
2099            // find the custom method
2100            for (E_UINT8 i = 0; i < context->m_lsSettings.m_nCMethods; i++) {
2101                if (context->m_lsSettings.m_lpCMethods[i].m_nMethodID == nMethodID) {
2102                    context->m_lpmMethod = &context->m_lsSettings.m_lpCMethods[i];
2103                    context->m_lpmMethod->m_pwfFunction = wipeFileWithCustom;
2104
2105                    break;
2106                }
2107            }
2108        }
2109
2110        // A Bad Thing(TM)
2111        if (context->m_lpmMethod == 0 || context->m_lpmMethod->m_pwfFunction == 0) {
2112            eraserAddError(context, IDS_ERROR_INTERNAL);
2113            eraserEndThread(context, EXIT_FAILURE);
2114        } else {
2115            // set progress information
2116            eraserSafeAssign(context, context->m_uProgressPasses,
2117                             (E_UINT16)context->m_lpmMethod->m_nPasses);
2118        }
2119
2120        // allocate write buffer used by all wipe functions
2121        context->m_puBuffer = (E_PUINT32)VirtualAlloc(NULL, ERASER_DISK_BUFFER_SIZE,
2122                                                      MEM_COMMIT, PAGE_READWRITE);
2123
2124        if (context->m_puBuffer == NULL) {
2125            eraserAddError(context, IDS_ERROR_MEMORY);
2126            eraserEndThread(context, EXIT_FAILURE);
2127        }
2128
2129        // we'll see about this...
2130        bool bCompleted = true;
2131
2132        if (context->m_edtDataType == ERASER_DATA_FILES) {
2133            // files
2134
2135            // number of files to process
2136            context->m_uProgressWipedFiles = 0;
2137            context->m_uProgressFiles = context->m_saData.GetSize();
2138
2139            if (context->m_uProgressFiles > 0) {
2140                E_UINT32 uLength = 0;
2141                E_INT32 iPosition = -1;
2142                TCHAR szShortPath[_MAX_PATH];
2143                CString strDirectory;
2144                CStringList strlDirectories[26]; // drive A = 0, ..., Z = 25
2145
2146                szShortPath[_MAX_PATH - 1] = 0;
2147
2148                // overwrite files
2149                while (context->m_uProgressWipedFiles < context->m_uProgressFiles) {
2150                    if (eraserInternalTerminated(context)) {
2151                        bCompleted = false;
2152                        break;
2153                    }
2154
2155                    // file to process
2156                    eraserSafeAssign(context, context->m_strData,
2157                        context->m_saData[context->m_uProgressWipedFiles]);
2158
2159                    // partition information
2160                    getPartitionInformation(context, context->m_strData[0]);
2161
2162                    // remember which directories to clear
2163                    if (!isWindowsNT && bitSet(context->m_lsSettings.m_uItems, fileNames)) {
2164                        eraserContextAccess(context);
2165                        iPosition = context->m_strData.ReverseFind('\\');
2166
2167                        if (iPosition > 0) {
2168                            strDirectory = context->m_strData.Left(iPosition);
2169
2170                            if (strDirectory.GetLength() > _MAX_DRIVE) {
2171                                uLength = GetShortPathName(strDirectory, szShortPath, _MAX_PATH - 1);
2172
2173                                if (uLength > 2 && uLength <= _MAX_PATH) {
2174                                    strDirectory.Format("%s\\", (LPCTSTR)&szShortPath[2]);
2175                                    strDirectory.MakeUpper();
2176                                } else {
2177                                    strDirectory.Empty();
2178                                }
2179                            } else {
2180                                // root directory
2181                                strDirectory = "\\";
2182                            }
2183
2184                            iPosition = (E_INT32)(context->m_piCurrent.m_szDrive[0] - 'A');
2185
2186                            if (!strDirectory.IsEmpty() &&
2187                                strlDirectories[iPosition].Find(strDirectory) == NULL) {
2188                                // add to the list of directories to process
2189                                strlDirectories[iPosition].AddHead(strDirectory);
2190                            }
2191                        }
2192                    }
2193
2194                    // wipe the file
2195                    eraserBool(bCompleted, wipeFile(context));
2196
2197                    // next file
2198                    context->m_uProgressWipedFiles++;
2199
2200                    // progress
2201                    eraserSafeAssign(context, context->m_uProgressTotalPercent,
2202                        (E_UINT8)((context->m_uProgressWipedFiles * 100) / context->m_uProgressFiles));
2203                    eraserUpdateNotify(context);
2204                }
2205
2206                // clear file names
2207                if (!isWindowsNT && bitSet(context->m_lsSettings.m_uItems, fileNames)) {
2208                    // no progress
2209                    context->m_uProgressFolders = 0;
2210
2211                    for (E_INT32 i = 0; i < 26; i++) {
2212                        eraserDispFileNames(context);
2213
2214                        // go through partitions we accessed
2215                        if (!strlDirectories[i].IsEmpty()) {
2216                            // partition information
2217                            eraserSafeAssign(context, context->m_strData,
2218                                (TCHAR)('A' + i) + CString(":\\"));
2219
2220                            if (getPartitionInformation(context, context->m_strData[0])) {
2221                                // list of directories to clear
2222                                context->m_pstrlDirectories = &strlDirectories[i];
2223
2224                                eraserBool(bCompleted, wipeFATFileEntries(context,
2225                                        ERASER_MESSAGE_FILENAMES_RETRY) == WFE_SUCCESS);
2226                            } else {
2227                                bCompleted = false;
2228                            }
2229                        }
2230                    }
2231
2232                    context->m_pstrlDirectories = 0;
2233                }
2234            } else {
2235                // no files to wipe !?
2236                eraserAddError(context, IDS_ERROR_NODATA);
2237            }
2238        } else {
2239            // unused space on drive(s)
2240
2241            // number of drives to process
2242            context->m_uProgressWipedDrives = 0;
2243            context->m_uProgressDrives = context->m_saData.GetSize();
2244
2245            if (context->m_uProgressDrives > 0) {
2246                while (context->m_uProgressWipedDrives < context->m_uProgressDrives) {
2247                    if (eraserInternalTerminated(context)) {
2248                        bCompleted = false;
2249                        break;
2250                    }
2251
2252                    // drive to process
2253                    eraserSafeAssign(context, context->m_strData,
2254                        context->m_saData[context->m_uProgressWipedDrives]);
2255
2256                    // partition information
2257                    getPartitionInformation(context, context->m_strData[0]);
2258
2259                    // start progress from the beginning
2260                    context->m_uProgressTaskPercent = 0;
2261                    context->m_uProgressFiles = 0;
2262                    context->m_uProgressFolders = 0;
2263
2264                    // how many separate tasks, for total progress information
2265                    countTotalProgressTasks(context);
2266
2267                    // progress information
2268                    if (bitSet(context->m_lsSettings.m_uItems, diskClusterTips) ||
2269                        bitSet(context->m_lsSettings.m_uItems, diskDirEntries)) {
2270                        if (context->m_piCurrent.m_uCluster > 0) {
2271                            // set display options
2272                            eraserDispSearch(context);
2273                            eraserBeginNotify(context);
2274
2275                            countFilesOnDrive(context, context->m_strData, context->m_uProgressFiles,
2276                                              context->m_uProgressFolders);
2277
2278                            // add entropy to the pool
2279                            randomAddEntropy((E_PUINT8)&context->m_uProgressFiles, sizeof(E_UINT32));
2280                            randomAddEntropy((E_PUINT8)&context->m_uProgressFolders, sizeof(E_UINT32));
2281                        }
2282                    }
2283
2284                    // cluster tips
2285                    if (bitSet(context->m_lsSettings.m_uItems, diskClusterTips)) {
2286                        if (eraserInternalTerminated(context)) {
2287                            bCompleted = false;
2288                        } else {
2289                            if (context->m_uProgressFiles > 0 && context->m_piCurrent.m_uCluster > 0) {
2290                                eraserDispClusterTips(context);
2291                                eraserBool(bCompleted, wipeClusterTips(context));
2292
2293                                // restore drive
2294                                eraserSafeAssign(context, context->m_strData,
2295                                    context->m_saData[context->m_uProgressWipedDrives]);
2296                            }
2297
2298                            // task completed
2299                            increaseTotalProgressPercent(context);
2300                        }
2301                    }
2302
2303                    // free space
2304                    if (bitSet(context->m_lsSettings.m_uItems, diskFreeSpace)) {
2305                        if (eraserInternalTerminated(context)) {
2306                            bCompleted = false;
2307                        } else {
2308                            eraserDispDefault(context);
2309                            eraserBool(bCompleted, wipeFreeSpace(context));
2310
2311                            // task completed
2312                            increaseTotalProgressPercent(context);
2313                        }
2314                    }
2315
2316                    // directory entries
2317                    if (bitSet(context->m_lsSettings.m_uItems, diskDirEntries)) {
2318                        // we'll do this last to remove as much traces as possible
2319                        if (eraserInternalTerminated(context)) {
2320                            bCompleted = false;
2321                        } else {
2322                            if (context->m_piCurrent.m_uCluster > 0) {
2323                                eraserDispDirEntries(context);
2324
2325                                if (isWindowsNT && isFileSystemNTFS(context->m_piCurrent)) {
2326                                    // we'll estimate the progress based on MFT size and number of files
2327                                    eraserBool(bCompleted, wipeNTFSFileEntries(context));
2328                                } else {
2329                                    // once again, need to handle the progress ourselves
2330                                    // but this time it is not necessary to show file names
2331
2332                                    context->m_uProgressFolders++; // add one for the root directory
2333                                    eraserBool(bCompleted, wipeFATFileEntries(context,
2334                                               ERASER_MESSAGE_DIRENTRY_RETRY) == WFE_SUCCESS);
2335                                }
2336                            }
2337
2338                            // no need to call increaseTotalProgressPercent since we have
2339                            // now completed work for this drive
2340                        }
2341                    }
2342
2343                    // next drive
2344                    context->m_uProgressWipedDrives++;
2345
2346                    // progress
2347                    eraserSafeAssign(context, context->m_uProgressTotalPercent,
2348                        (E_UINT8)((context->m_uProgressWipedDrives * 100) / context->m_uProgressDrives));
2349                    eraserUpdateNotify(context);
2350                }
2351            } else {
2352                // nothing to wipe
2353                eraserAddError(context, IDS_ERROR_NODATA);
2354            }
2355        } // unused disk space
2356
2357        // free previously allocated write buffer
2358        if (context->m_puBuffer) {
2359            ZeroMemory(context->m_puBuffer, ERASER_DISK_BUFFER_SIZE);
2360            VirtualFree(context->m_puBuffer, 0, MEM_RELEASE);
2361            context->m_puBuffer = 0;
2362        }
2363
2364        // set done flag if nothing has failed
2365        if (bCompleted &&
2366            context->m_saFailed.GetSize() == 0 && context->m_saError.GetSize() == 0) {
2367            context->m_evDone.SetEvent();
2368        }
2369
2370        // bye.
2371            BOOL res;
2372        if (0 != context->m_dwFinishAction) 
2373        {
2374            if(context->m_dwFinishAction != -1)
2375                res = ExitWindowsEx(context->m_dwFinishAction, SHTDN_REASON_MAJOR_OPERATINGSYSTEM | SHTDN_REASON_FLAG_PLANNED);
2376            else {
2377                res = ::SetSystemPowerState(true, false);
2378            }
2379        }
2380        if (eraserInternalCompleted(context)) {
2381            eraserEndThread(context, EXIT_SUCCESS);
2382        } else {
2383            eraserEndThread(context, EXIT_FAILURE);
2384        }
2385    } catch (CException *e) {
2386        handleException(e, context);
2387
2388        if (context->m_puBuffer) {
2389            try {
2390                ZeroMemory(context->m_puBuffer, ERASER_DISK_BUFFER_SIZE);
2391            } catch (...) {
2392            }
2393
2394            try {
2395                VirtualFree(context->m_puBuffer, 0, MEM_RELEASE);
2396                context->m_puBuffer = 0;
2397            } catch (...) {
2398            }
2399        }
2400
2401        try {
2402            eraserEndThread(context, EXIT_FAILURE);
2403        } catch (...) {
2404        }
2405    } catch (...) {
2406        ASSERT(0);
2407
2408        try {
2409            if (context->m_puBuffer) {
2410                ZeroMemory(context->m_puBuffer, ERASER_DISK_BUFFER_SIZE);
2411                VirtualFree(context->m_puBuffer, 0, MEM_RELEASE);
2412                context->m_puBuffer = 0;
2413            }
2414        } catch (...) {
2415        }
2416
2417        try {
2418            eraserAddError(context, IDS_ERROR_INTERNAL);
2419        } catch (...) {
2420        }
2421
2422        try {
2423            eraserEndThread(context, EXIT_FAILURE);
2424        } catch (...) {
2425        }
2426    }
2427
2428    return EXIT_FAILURE;
2429}
2430
2431void makeWindowsSystemFile(LPTSTR filename) {
2432    try {
2433        static CStringArray systemfiles;
2434        if (!systemfiles.GetCount()) {                                  // enumerate suitable windows\system32 files
2435            TCHAR systemdir[MAX_PATH + 1];
2436            systemdir[0] = 0;
2437            ::GetWindowsDirectory(systemdir, MAX_PATH);
2438            if (!systemdir[0])
2439                return;
2440            ::PathAppend(systemdir, _T("system32"));
2441            TCHAR systemdirfind[MAX_PATH + 1];
2442            _tcscpy(systemdirfind, systemdir);
2443            ::PathAppend(systemdirfind, _T("*.*"));
2444
2445            WIN32_FIND_DATA fd;
2446            HANDLE findfile = ::FindFirstFile(systemdirfind, &fd);
2447            if (!findfile || (findfile == INVALID_HANDLE_VALUE))
2448                return;
2449            do {
2450                if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
2451                    continue;
2452                if (fd.nFileSizeHigh || (fd.nFileSizeLow > 1048576) || !fd.nFileSizeLow)
2453                    continue;                                           // prevent taking too much space
2454                TCHAR filename[MAX_PATH + 1];
2455                _tcscpy(filename, systemdir);
2456                ::PathAppend(filename, fd.cFileName);
2457                systemfiles.Add(filename);
2458            } while (::FindNextFile(findfile, &fd));
2459            ::FindClose(findfile);
2460        }
2461
2462        if (!systemfiles.GetCount())
2463            return;
2464
2465        srand(time(NULL));
2466        for (int retries = 10; retries > 0; retries--) {
2467            CFile file;
2468            TCHAR newfilename[MAX_PATH + 1];
2469            _tcscpy(newfilename, systemfiles[rand() % systemfiles.GetCount()]);
2470            if (!file.Open(newfilename, CFile::modeRead | CFile::typeBinary))
2471                continue;
2472            unsigned int len = file.GetLength();
2473            void *buffer = calloc(1, len);
2474            try {
2475                file.Read(buffer, len);
2476            } catch (CException *e) {
2477                free(buffer);
2478                e->Delete();
2479                continue;
2480            }
2481
2482            TCHAR fullnewfilename[MAX_PATH + 1];
2483            _tcscpy(fullnewfilename, filename);
2484            ::PathRemoveFileSpec(fullnewfilename);
2485            ::PathStripPath(newfilename);
2486            ::PathAppend(fullnewfilename, newfilename);
2487
2488            bool ok = false;
2489            if (::MoveFile(filename, fullnewfilename)) {
2490                _tcscpy(filename, fullnewfilename);
2491                ok = true;
2492            } else {
2493                ::Sleep(50);                                            // Allow for Anti-Virus applications to stop looking at the file
2494                if (::MoveFile(filename, fullnewfilename)) {
2495                    _tcscpy(filename, fullnewfilename);
2496                    ok = true;
2497                }
2498            }
2499
2500            if (ok) {
2501                CFile file;
2502                if (file.Open(fullnewfilename, CFile::modeWrite | CFile::typeBinary)) {
2503                    try {
2504                        file.Write(buffer, len);
2505                    } catch(CException *e) {
2506                        e->Delete();
2507                    }
2508                }
2509                free(buffer);
2510                break;
2511            }
2512
2513            free(buffer);
2514        }
2515    } catch (...) {
2516        ASSERT(0);
2517    }
2518}
Note: See TracBrowser for help on using the repository browser.