2010年10月26日 星期二

Cemail.vol backup / restore

The original post is on MSDN develop forums, cause the post there sometimes get lost, and the coding style is totally crash by HTML. So, I made one copy here for backup and clear the coding style for easy read.

Below link it the original post:

http://social.msdn.microsoft.com/Forums/en-US/vssmartdevicesnative/thread/d1d8c95a-9366-4acf-8bac-b6862bfc2f79

This post share source code of two functions: BackupMain() and RestoreMain() to backup and restore cemail.vol, The idea is very simple.

When doing backup, the method create a cemail_backup.vol (CEDB, too), enumerate all database and records from ceminl.vol and make a backup copy to cemail_backup.vol.

When doing restore, the method clear all records in cemail.vol, and then do the same thing as backup, just different direction.

Here is the BackupMail() function, used to backup cemail.vol:

BOOL BackupMail()
{
    CEGUID ceguidCemail;
    CEGUID ceguidBackUp;
    CREATE_INVALIDGUID(&ceguidCemail);
    CREATE_INVALIDGUID(&ceguidBackUp);

    if (!CeMountDBVol(&ceguidCemail, L"cemail.vol", OPEN_EXISTING))
    {
        return FALSE;   
    }

    if (!CeMountDBVol( &ceguidBackUp, L"\\cemail_backup.vol", CREATE_ALWAYS))
    {
        return FALSE;
    }

    HANDLE hDatabaseEnumHandle = INVALID_HANDLE_VALUE;

    if ((hDatabaseEnumHandle = CeFindFirstDatabaseEx(&ceguidCemail, 0)) == INVALID_HANDLE_VALUE)
    {
        return FALSE;
    }

    CEOID ceoidFind = 0;

    while (ceoidFind = CeFindNextDatabaseEx(hDatabaseEnumHandle, NULL))
    {
        HANDLE hDBOpened = INVALID_HANDLE_VALUE;

        hDBOpened = CeOpenDatabaseEx(
            &ceguidCemail,
            &ceoidFind,
            NULL,
            NULL,
            CEDB_AUTOINCREMENT,
            NULL);

        if (hDBOpened == INVALID_HANDLE_VALUE)
        {
            DWORD error = GetLastError();
            return FALSE;
        }

        BY_HANDLE_DB_INFORMATION hDBOpenedInfo;
        hDBOpenedInfo.wVersion = 1;

        if (!CeGetDBInformationByHandle(hDBOpened, &hDBOpenedInfo))
        {
            DWORD dwError = GetLastError();
            return FALSE;
        }

        CEOIDINFOEX cdDb;
        CEOID ceoidFindRecorde = NULL;
        CeOidGetInfoEx2(&ceguidCemail,ceoidFindRecorde, &cdDb);
        CEOID ceoidDBaseCopy = 0;

        if (!(ceoidDBaseCopy = CeCreateDatabaseEx2(&ceguidBackUp, &hDBOpenedInfo.infDatabase)))
        {
            DWORD dwErro = GetLastError();
            return FALSE;
        }

        HANDLE hDBaseCopyHandle = INVALID_HANDLE_VALUE;

        hDBaseCopyHandle = CeOpenDatabaseEx(\
            &ceguidBackUp,
            &ceoidDBaseCopy,
            hDBOpenedInfo.infDatabase.szDbaseName,
            0,
            CEDB_AUTOINCREMENT,
            NULL);

        if (hDBaseCopyHandle == INVALID_HANDLE_VALUE)
        {
            return FALSE;
        }

        hDBOpenedInfo.wVersion = 1;

        if (!CeGetDBInformationByHandle(hDBaseCopyHandle, &hDBOpenedInfo))
        {
            DWORD dwError = GetLastError();
            return FALSE;
        }

        DWORD dwCpt = 0;
        CEOID ceoidFindRecord = 0;
        WORD dwPropId = 0;
        CEPROPVAL* Buffer = NULL;
        DWORD dwSizeOfBuffer = 0;
        HANDLE hHeap = GetProcessHeap();

        if (hHeap == NULL)
            return FALSE;

        while (ceoidFindRecord = CeReadRecordPropsEx(
            hDBOpened,
            CEDB_ALLOWREALLOC,
            &dwPropId,NULL,
            (LPBYTE*)&Buffer,
            &dwSizeOfBuffer,
            hHeap))
        {
            dwCpt++;
        }

        if (GetLastError() != ERROR_NO_MORE_ITEMS)
            return false;

        free(Buffer);
        Buffer = NULL;

        CeSeekDatabaseEx(hDBOpened, CEDB_SEEK_BEGINNING, 0, 0, NULL);

        ceoidFindRecord = 0;
        DWORD dwNumberOfRecordFound = 0;

        while (dwNumberOfRecordFound++ < dwCpt)
        {
            ceoidFindRecord = CeReadRecordPropsEx(
                hDBOpened,
                CEDB_ALLOWREALLOC,
                &dwPropId,
                NULL,
                (LPBYTE*)&Buffer,
                &dwSizeOfBuffer,
                hHeap);

            if (!ceoidFindRecord)
            {
                DWORD dwError = GetLastError();
                return FALSE;
            }

            CEOID ceoidRecordAdd;

            ceoidRecordAdd = CeWriteRecordProps(
                hDBaseCopyHandle,
                0,
                dwPropId,
                Buffer);

            if (!ceoidRecordAdd)
            {
                DWORD dwError = GetLastError();
                return FALSE;
            }

            free(Buffer);
            Buffer = NULL;
        }

        CloseHandle(hDBaseCopyHandle);
        hDBaseCopyHandle = NULL;
    }

    if (!CeFlushDBVol(&ceguidCemail))
        return FALSE;

    if (!CeFlushDBVol(&ceguidBackUp))
        return FALSE;

    if (!CeUnmountDBVol(&ceguidCemail))
        return FALSE;

    if (!CeUnmountDBVol(&ceguidBackUp))
        return FALSE;

    return TRUE;
}

And this is the RestoreMail() function, user to restore cemail.vol:

BOOL RestoreMail()
{
    CEGUID ceguidCemail;
    CEGUID ceguidBackUp;
    CREATE_INVALIDGUID(&ceguidCemail);
    CREATE_INVALIDGUID(&ceguidBackUp);

    if (!CeMountDBVol(&ceguidCemail, L"cemail.vol", OPEN_EXISTING))
    {
        return FALSE;
    }

    if (!CeMountDBVol(&ceguidBackUp, L"cemail_backup.vol", OPEN_EXISTING))
    {
        return FALSE;
    }

    HANDLE hDatabaseEnumHandle = INVALID_HANDLE_VALUE;

    if ((hDatabaseEnumHandle = CeFindFirstDatabaseEx(&ceguidBackUp, 0)) == INVALID_HANDLE_VALUE)
    {
        return FALSE;
    }

    CEOID ceoidFind = 0;

    // Delete old value

    HANDLE hRemoveHandle = INVALID_HANDLE_VALUE;

    CEOID oldid = 0;

    if ((hRemoveHandle = CeFindFirstDatabaseEx(&ceguidCemail, 0)) == INVALID_HANDLE_VALUE)
    {
        return FALSE;
    }

    while (oldid = CeFindNextDatabaseEx(hRemoveHandle, NULL))
    {
        HANDLE oldHandle = INVALID_HANDLE_VALUE;

        oldHandle = CeOpenDatabaseEx(
            &ceguidCemail,
            &oldid,
            NULL,
            NULL,
            CEDB_AUTOINCREMENT,
            NULL);

        if (oldHandle == INVALID_HANDLE_VALUE)
            return FALSE;

        BY_HANDLE_DB_INFORMATION hDBOldOpenedInfo;
        hDBOldOpenedInfo.wVersion = 1;

        if (!CeGetDBInformationByHandle(oldHandle, &hDBOldOpenedInfo))
            return FALSE;

        DWORD dwOldCpt = 0;
        CEOID ceoOldidFindRecord = 0;
        WORD dwOldPropId = 0;
        CEPROPVAL* oldBuffer = NULL;
        DWORD dwOldSizeOfBuffer = 0;
        HANDLE hOldHeap = GetProcessHeap();

        if (hOldHeap == NULL)
            return FALSE;

        while (ceoOldidFindRecord = CeReadRecordPropsEx(
            oldHandle,
            CEDB_ALLOWREALLOC,
            &dwOldPropId,
            NULL,
            (LPBYTE*)&oldBuffer,
            &dwOldSizeOfBuffer,
            hOldHeap))
        {
            dwOldCpt++;
        }

        if (GetLastError() != ERROR_NO_MORE_ITEMS)
            return false;

        free(oldBuffer);
        oldBuffer = NULL;

        CeSeekDatabaseEx(oldHandle, CEDB_SEEK_BEGINNING, 0, 0, NULL);

        ceoOldidFindRecord = 0;
        DWORD dwOldNumberOfRecordFound = 0;

        while (dwOldNumberOfRecordFound++ < dwOldCpt)
        {
            ceoOldidFindRecord = CeReadRecordPropsEx(
                oldHandle,
                CEDB_ALLOWREALLOC,
                &dwOldPropId,
                NULL,
                (LPBYTE*)&oldBuffer,
                &dwOldSizeOfBuffer,
                hOldHeap);

            CeDeleteRecord(oldHandle,ceoOldidFindRecord);
        }

        CloseHandle(oldHandle);
        oldHandle = NULL;
    }

    CloseHandle(hRemoveHandle);
    hRemoveHandle = NULL;

    while (ceoidFind = CeFindNextDatabaseEx(hDatabaseEnumHandle, NULL))
    {
        HANDLE hDBOpened = INVALID_HANDLE_VALUE;

        hDBOpened = CeOpenDatabaseEx(
            &ceguidBackUp,
            &ceoidFind,
            NULL,
            NULL,
            CEDB_AUTOINCREMENT,
            NULL);

        if (hDBOpened == INVALID_HANDLE_VALUE)
        {
            DWORD error = GetLastError();
            return FALSE;
        }

        BY_HANDLE_DB_INFORMATION hDBOpenedInfo;
        hDBOpenedInfo.wVersion = 1;

        if (!CeGetDBInformationByHandle(hDBOpened, &hDBOpenedInfo))
        {
            return FALSE;
        }

        CEOID ceoidDBaseOriginal = 0;
        HANDLE hDBaseOriginalHandle = INVALID_HANDLE_VALUE;

        hDBaseOriginalHandle = CeOpenDatabaseEx2(
            &ceguidCemail,
            &ceoidDBaseOriginal,
            hDBOpenedInfo.infDatabase.szDbaseName,
            NULL,
            CEDB_AUTOINCREMENT,
            NULL);

        if (hDBaseOriginalHandle == INVALID_HANDLE_VALUE)
        {
            if (GetLastError() == ERROR_FILE_NOT_FOUND)
            {
                CEOID ceoidDBaseCopy = 0;

                // Trap error only if not a duplicate/existing db name

                if(!(ceoidDBaseCopy = CeCreateDatabaseEx2(&ceguidCemail,
                    &hDBOpenedInfo.infDatabase)))
                {
                    DWORD dwError = GetLastError();
                    return FALSE;
                }
            }
            else
            {
                return FALSE;
            }
        }

        ceoidDBaseOriginal = 0;
        hDBaseOriginalHandle = INVALID_HANDLE_VALUE;

        hDBaseOriginalHandle = CeOpenDatabaseEx2(
            &ceguidCemail,
            &ceoidDBaseOriginal,
            hDBOpenedInfo.infDatabase.szDbaseName,
            NULL,
            CEDB_AUTOINCREMENT,
            NULL);

        if (hDBaseOriginalHandle == INVALID_HANDLE_VALUE)
        {
            return FALSE;
        }

        WORD dwPropId = 0;
        CEPROPVAL* Buffer = NULL;
        DWORD dwSizeOfBuffer = 0;
        HANDLE hHeap = GetProcessHeap();

        if (hHeap == NULL)
            return FALSE;

        BOOL bDBIsEmpty = FALSE;
        CEOID ceoidFindRecord = 0;

        while (!bDBIsEmpty)
        {
            ceoidFindRecord = CeReadRecordPropsEx(
                hDBOpened,
                CEDB_ALLOWREALLOC,
                &dwPropId,
                NULL,
                (LPBYTE*)&Buffer,
                &dwSizeOfBuffer,
                hHeap);

            if (!ceoidFindRecord)
            {
                if (GetLastError() != ERROR_NO_MORE_ITEMS)
                    return FALSE;
                else
                    bDBIsEmpty = TRUE;
            }
            else
            {
                CEPROPVAL* temp;
                temp = (CEPROPVAL*)malloc(dwSizeOfBuffer);

                memcpy(temp, Buffer, dwSizeOfBuffer);

                CEOID ceoidRecordAdd = 0;
                ceoidRecordAdd = CeWriteRecordProps(
                    hDBaseOriginalHandle,
                    0,
                    dwPropId,
                    Buffer);

                if (!ceoidRecordAdd)
                    return FALSE;

                free(temp);
                temp = NULL;
                free(Buffer);
                Buffer = NULL;
            }
        }
    }

    if (!CeFlushDBVol(&ceguidCemail)) return FALSE;
    if (!CeFlushDBVol(&ceguidBackUp)) return FALSE;
    if (!CeUnmountDBVol(&ceguidCemail)) return FALSE;
    if (!CeUnmountDBVol(&ceguidBackUp)) return FALSE;

    return TRUE;
}

I never tested it yet, and not really study the code carefully. But logically it should work  fine. Actually, I still image that I can stop the application & service locked cemial.vol, and then I can just do a easy file copy…吐舌頭

沒有留言:

張貼留言