Search code examples
c++databasewinapiextensible-storage-engine

How to restore / recover ESE DB using Microsoft's API


What I'm basically trying to achieve here is a proper way to restore a dirty DB.

esentutl /mh db.dat yields the following output

enter image description here

which is fine because i took a copy of the DB while being opened by another program.

is it possible to open the DB using microsoft's JetBlue Api without the proper log & chk files? (ESEDatabaseView does it somehow, nirsoft.net)

If such case isn't possible with Microsoft's API, and logs are needed, what is the correct way of recovering the db(i've changed my DB's & logs location)

here's my code:

   wpath p2 = L"C:\\m.db";
        ULONG unPageSize;
        long jet_err = JetGetDatabaseFileInfoW(p2.file_string().c_str(), &unPageSize, sizeof(unPageSize), JET_DbInfoPageSize);
        if (jet_err != JET_errSuccess) {
            return false;
        }

        jet_err = JetSetSystemParameter( NULL, NULL, JET_paramDatabasePageSize, unPageSize, NULL);
        if (jet_err != JET_errSuccess) {
            return false;
        }

        jet_err = JetSetSystemParameter( NULL, NULL, JET_paramRecovery, 0, "Off");
        if (jet_err != JET_errSuccess) {
            return false;
        }

        jet_err = JetSetSystemParameter( NULL, NULL, JET_paramLogFilePath, 0, "C:\\");
        if (jet_err != JET_errSuccess) {
            return false;
        }

        jet_err = JetSetSystemParameter( NULL, NULL, JET_paramSystemPath, 0, "C:\\");
        if (jet_err != JET_errSuccess) {
            return false;
        }

        jet_err = JetSetSystemParameter( NULL, NULL, JET_paramAlternateDatabaseRecoveryPath, 0, "C:\\");
        if (jet_err != JET_errSuccess) {
            return false;
        }

        JET_INSTANCE instance = { 0 };
        jet_err = JetCreateInstance(&instance, "instance");
        if (jet_err != JET_errSuccess) {
            return false;
        }

        jet_err = JetInit(&instance);
        if (jet_err != JET_errSuccess) {
            JetTerm(instance);
            return false;
        }

        JET_SESID sesid;
        jet_err = JetBeginSession(instance, &sesid, 0, 0);
        if (jet_err != JET_errSuccess) {
            JetTerm(instance);
            return false;
        }

        jet_err = JetAttachDatabaseW( sesid, pathESEDbLocation.file_string().c_str(), JET_bitDbReadOnly);
        if (jet_err != JET_errSuccess) {
            JetEndSession(sesid, 0);
            JetTerm(instance);
            return false;
        }

JetAttachDatabaseW fails with -550 JET_errDatabaseDirtyShutdown

Edit I have found out that a simple esenutl /p data.dat call without any checkpoint and log files also fixes the issue. I've tried using the JetExternalRestoreW command but it keeps throwing #define JET_errFileNotFound -1811 /* File not found */

JET_RSTMAP_W p = {L"C:/Users/user/AppData/Local/Temp/db/db.dat", L"C:/Users/user/AppData/Local/Temp/db/db.dat"};
jet_err = JetExternalRestoreW(nullptr, L"C:/Users/user/AppData/Local/Temp/db/", &p, 1,L"C:/Users/igalk/AppData/Local/Temp/db/",  0, 0, nullptr);

Solution

  • A dirty shutdown doesn't mean that it's missing the log and check files... So that might be a separate issue.

    You example above has things in the wrong order...

    You can configure your application to automatically attempt to clear the "dirty shutdown" by adding the following after JetCreateInstance and before JetInit:

    Api.JetSetSystemParameter(instance, JET_SESID.Nil, Server2003Param.AlternateDatabaseRecoveryPath, 0, Path.GetDirectoryName(databasePath));
    

    (above sample is in C#, but you get the point...)

    The last parameter is the location where you'd like the repaired database to appear, so most likely that'd be the same directory as the dirty database file.