source: trunk/EraserDll/Eraser.cpp @ 32

Revision 32, 76.4 KB checked in by lowjoel, 7 years ago (diff)

-Commit my fix for files which have filenames which are too long for the standard Windows filename handling to work
-Commit my fix to ignore files which are actually junctions or symbolic links
-UNC files are now ignored during free space wipes
-Silenced a few unused formal parameter warnings

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