source: trunk/EraserDll/Eraser.cpp @ 834

Revision 834, 77.8 KB checked in by lowjoel, 6 years ago (diff)

Don't complain that there are no files to erase. Fixes #126.

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