RESTTEST.CPP

// --resttest.cpp--------------------------------------------------------------- 
//
// Backup restore sample.
//
// Copyright (C) Microsoft Corp. 1986-1996. All Rights Reserved.
// -----------------------------------------------------------------------------

#include "edk.h"
#include <edbback.h>
#include <edbbcli.h>
#include <time.h>
#include "backtest.h"

DWORD
cbReadSize = 0x10000;

CHAR
rgchComputerName[ MAX_COMPUTERNAME_LENGTH ];

ERR
ErrRestoreFile(
HANDLE hBackup,
EDB_RSTMAP *rgrstmap,
I *irgRestMap,
SZ szDatabaseLocationList,
SZ *pszBackupLogDirectory = NULL,
PBOOL pfSetGen = NULL,
PDWORD gen = NULL
);


ERR
ErrReadStructure(
HANDLE hFile,
VOID *pvStruct,
CB cbStruct
)
{
CB cbRead = 0;

if (!ReadFile(hFile, pvStruct, cbStruct, (PDWORD)&cbRead, NULL))
{
printf("Unable to read log headers from backup file %d\n", GetLastError());
return(GetLastError());
}

if (cbRead != cbStruct)
{
printf("Unable to read all of log header from backup file\n");
return(1);
}
return(ERROR_SUCCESS);
}

ERR
ErrReadHeader(
HANDLE hFile,
PBackupHeader bh
)
{
ERR err = 0;
if (err = ErrReadStructure(hFile, bh, sizeof(BackupHeader)))
{
printf("Unable to read log headers from backup file: %d\n", err);
return(err);
}

if (bh->ulSignature != BACKUP_SIGNATURE)
{
printf("Log signature does not match, backup is probably corrupt\n");
return(1);
}
return(ERROR_SUCCESS);
}

ERR
ErrReadHeader(
HANDLE hFile,
PBackupFile bf
)
{
ERR err = 0;
if (err = ErrReadStructure(hFile, bf, sizeof(BackupFile)))
{
printf("Unable to read log headers from backup file: %d\n", err);
return(err);
}

if (bf->ulFileSignature != FILE_SIGNATURE)
{
printf("Log signature does not match, backup is probably corrupt\n");
return(1);
}
return(ERROR_SUCCESS);
}

ERR
ErrReadHeader(
HANDLE hFile,
PLogHeader lh
)
{
ERR err = 0;
if (err = ErrReadStructure(hFile, lh, sizeof(LogHeader)))
{
printf("Unable to read log headers from backup file: %d\n", err);
return(err);
}

if (lh->ulLogSignature != LOG_SIGNATURE)
{
printf("Log signature does not match, backup is probably corrupt\n");
return(1);
}
return(ERROR_SUCCESS);
}

SZ
SzFindBFT(
SZ szDatabaseLocationList,
BFT bft
)
{
SZszDatabaseLocation = szDatabaseLocationList;

while (*szDatabaseLocation)
{
BFT bftLocation = *szDatabaseLocation++;

if (bftLocation == bft)
{
return szDatabaseLocation;
break;
}

szDatabaseLocation += strlen(szDatabaseLocation)+1;
}

return NULL;
}

ERR
ErrRestoreFile(
HANDLE hBackup,
EDB_RSTMAP *prstmap,
I *pirgrstmap,
SZ szDatabaseLocationList,
SZ *pszBackupLogDirectory,
PBOOL pfSetGen,
PDWORD gen
)
{
ERR err = 0;
BackupFile bf = {0};
SZ szNewFileName = NULL;
HANDLE hRestoreFile = NULL;
CB cbRead = 0;
BFT bftFile = 0;
SZ szFileName = NULL;
PVOID pvBuffer = NULL;
char rgchDrive[_MAX_DRIVE] = {0};
char rgchDir[_MAX_DIR] = {0};
char rgchFileName[_MAX_FNAME] = {0};
char rgchExtension[_MAX_EXT] = {0};
LARGE_INTEGER liBytesRemaining = {0};
DWORD cbToRead = 0;

//
//Read the backup header for the file.
//

if (pfSetGen)
*pfSetGen = fFalse;

err = ErrReadHeader(hBackup, &bf);

szFileName = new char[bf.cbFileNameLength];

if (szFileName == NULL)
{
printf("Error allocating space for database name\n");
err = ERROR_NOT_ENOUGH_MEMORY;
goto cleanup;
}

if (!ReadFile(hBackup, szFileName, bf.cbFileNameLength, (PDWORD)&cbRead, NULL))
{
printf("Unable to read file name from backup file: %d\n", GetLastError());
err = GetLastError();
goto cleanup;
}

//
//Save away the backup file type of this file.
//

bftFile = bf.bft;

//
//Crack the incoming database name to determine the file name.
//

_splitpath(szFileName, rgchDrive, rgchDir, rgchFileName, rgchExtension);

if (gen != NULL)
{
//
//We want to find out the generation of this file if it's a log file.
//

if (strnicmp(rgchFileName, "EDB", 3) == 0)
{
if (stricmp(rgchExtension, ".LOG") == 0)
{
//
//log file generations are hex digits.
//

*gen = strtoul(&rgchFileName[3], NULL, 16);
if (pfSetGen)
*pfSetGen = fTrue;

//
//If we want to find out the log directory, return it.
//

if (pszBackupLogDirectory != NULL)
{
if (rgchDir[strlen(rgchDir)-1] == '\\')
{
rgchDir[strlen(rgchDir)-1] = '\0';
}

//
//Save away the backup log directory if needed.
//

*pszBackupLogDirectory = strdup(rgchDir);
}

}
}
}

//
//Ok, now find out where we are goingto put this file.
//


//
//First scan for an exact match on BFT.
//

szNewFileName = SzFindBFT(szDatabaseLocationList, bftFile);

if (szNewFileName == NULL)
{
//
//Ok, we didn't find it exactly, let's try to find it's directory.
//

if (bftFile & BFT_LOG_DIRECTORY)
{
SZ szLogDir = NULL;

//
//This guy goes into the log directory. Find out where that is.
//

szLogDir = SzFindBFT(szDatabaseLocationList, BFT_LOG_DIR);

if (szLogDir == NULL)
{
printf("Could not find log directory");
err = ERROR_FILE_NOT_FOUND;
goto cleanup;
}

szNewFileName = new char[strlen(szLogDir)+1+strlen(rgchFileName)+strlen(rgchExtension)+2];
strcpy(szNewFileName, szLogDir);
strcat(szNewFileName, "\\");
strcat(szNewFileName, rgchFileName);
strcat(szNewFileName, rgchExtension);
}
else if (bftFile & BFT_DATABASE_DIRECTORY)
{
printf("Don't support inexact match in datbase directory yet");
err = ERROR_FILE_NOT_FOUND;
}
}

//
//If this goes into the database directory, it needs to go into the RSTMAP.
//

if (bftFile & BFT_DATABASE_DIRECTORY)
{
prstmap[*pirgrstmap].szDatabaseName = szFileName;
prstmap[*pirgrstmap].szNewDatabaseName = strdup(szNewFileName);
*pirgrstmap+=1;
}

//
//If the munged name in the database is on our current machine, then unmunge the name for efficency.
//

if (szNewFileName[0] == '\\' && szNewFileName[1] == '\\')
{
//
//Ok, this is a munged file name.
//
SZ szBackslash = strchr(&szNewFileName[2], '\\');

if (szBackslash != NULL)
{
if (_strnicmp(&szNewFileName[2], rgchComputerName, szBackslash-&szNewFileName[2]) == 0)
{
//
//Ok, the current computer name matches the munged name, we want to munge the
// destination file specified to match the local name.
//

szNewFileName = _strdup(szBackslash+1);

if (szNewFileName[1] == '$')
{
szNewFileName[1] = ':';
}
}
}
}

hRestoreFile = CreateFile(szNewFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
FILE_FLAG_SEQUENTIAL_SCAN, NULL);

if (hRestoreFile == INVALID_HANDLE_VALUE)
{
err = GetLastError();

if (ERROR_SHARING_VIOLATION==err)
{
printf("Unable to open %s. Make sure the Store service has been "
"stopped before restoring.\n", szNewFileName, GetLastError());
}
else
{
printf("Unable to open file %s for restore: %d\n", szNewFileName, err);
}
goto cleanup;
}

liBytesRemaining = bf.liFileSize;

pvBuffer = (void *)new char[cbReadSize];

if (pvBuffer == NULL)
{
printf("Unable to allocate buffer for file restore.\n");
err = 1;
goto cleanup;
}

cbToRead = cbReadSize;

while (liBytesRemaining.QuadPart != 0)
{
DWORD cbRead = 0;
DWORD cbWritten = 0;

if (liBytesRemaining.QuadPart < cbReadSize)
{
cbToRead = liBytesRemaining.LowPart;
}

if (!ReadFile(hBackup, pvBuffer, cbToRead, &cbRead, NULL))
{
printf("Unable to read from restore file: %d\n", GetLastError());
err = GetLastError();
goto cleanup;
}

if (cbRead != cbToRead)
{
printf("Unable to read from restore file: %d\n", GetLastError());
err = GetLastError();
goto cleanup;
}

if (!WriteFile(hRestoreFile, pvBuffer, cbRead, &cbWritten, NULL))
{
printf("Unable to write to restored file: %d\n", GetLastError());
err = GetLastError();
goto cleanup;
}

if (cbRead != cbWritten)
{
printf("Unable to write to restored file: %d\n", GetLastError());
err = GetLastError();
goto cleanup;
}

liBytesRemaining.QuadPart -= cbRead;
}

CloseHandle(hRestoreFile);

err = ERROR_SUCCESS;

cleanup:
if (pvBuffer)
{
delete pvBuffer;
}

return(err);
}

int
_cdecl
main (int cArg, char *rgszArgv[])
{
I irgsz = 0;
BOOL fDsa = fFalse;
BOOL fMdb = fFalse;

SZ szBackupFile = DEF_BACKUP_FILE;
SZ szBackupServer = NULL;
HANDLE hBackupFile = NULL;
DWORD cbComputerName = sizeof(rgchComputerName);
SZ szDatabaseLocationList = NULL;
DWORD cbLocationList = 0;

BOOL fInvalidArg = fFalse;

if (!GetComputerName(rgchComputerName, &cbComputerName))
{
printf("Unable to query computer name: %d\n", GetLastError());
return(GetLastError());
}

for (irgsz = 1; irgsz < cArg ; irgsz += 1)
{
if (rgszArgv[irgsz][0] == '-' || rgszArgv[irgsz][0]=='/' )
{
if (toupper(rgszArgv[irgsz][1]) == 'B')
{
szBackupFile = (rgszArgv[irgsz][2] == ':' ? &rgszArgv[irgsz][3] : rgszArgv[++irgsz]);
}
else if (toupper(rgszArgv[irgsz][1]) == 'S')
{
szBackupServer = (rgszArgv[irgsz][2] == ':' ? &rgszArgv[irgsz][3] : rgszArgv[++irgsz]);
}
else
{
fInvalidArg = fTrue;
break;
}
}
}

if (fInvalidArg || cArg <= 1)
{
printf("\nUsage: RestTest\t -S:<Server>\n\t\t -B:<Backup File>\n");
return(0);
}

if (szBackupServer == NULL)
{
szBackupServer = rgchComputerName;
}

//
//Open up the backup file for write access.
//

hBackupFile = CreateFile(szBackupFile,
GENERIC_READ,
0,
NULL,
OPEN_EXISTING,
FILE_FLAG_SEQUENTIAL_SCAN,
NULL
);
if (hBackupFile == INVALID_HANDLE_VALUE)
{
printf("Unable to open backup file %s: %d\n", szBackupFile, GetLastError());
return(GetLastError());
}

BackupHeader bh = {0};
CB cbRead = 0;

ERR err = 0;

err = ErrReadHeader(hBackupFile, &bh);

if (err != ERROR_SUCCESS)
{
return(err);
}

SZ szRestoreAnnotation = NULL;
szRestoreAnnotation = new char[bh.cbDatabaseNameLength];

if (szRestoreAnnotation == NULL)
{
printf("Out of memory error\n");
return(1);
}
if (!ReadFile(hBackupFile, szRestoreAnnotation, bh.cbDatabaseNameLength, (PDWORD)&cbRead, NULL))
{
printf("Unable to read from backup file %s: %d\n", szBackupFile, GetLastError());
return(GetLastError());
}

if (cbRead != bh.cbDatabaseNameLength)
{
printf("Unable to read all of database name from backup file %s\n", szBackupFile);
return(GetLastError());
}

if (strlen(szRestoreAnnotation) != (ULONG)bh.cbDatabaseNameLength-1)
{
printf("Database name %s corrupted in backup file %s\n", szRestoreAnnotation, szBackupFile);
return(GetLastError());
}

printf("Now performing component specific restoration\n");

HBC hbc = NULL;

err = HrRestorePrepare(szBackupServer, szRestoreAnnotation, &hbc);

if (err != ERROR_SUCCESS)
{
printf("Unable to connect to restore provider on server %s\n", szBackupServer);
return(err);
}

err = HrRestoreGetDatabaseLocations(
hbc,
&szDatabaseLocationList,
&cbLocationList);

if (err != ERROR_SUCCESS)
{
printf("Unable to query database locations on %s\n", szBackupServer);
return(err);
}


C cRemainingBackupFiles = bh.cBackupFiles;

//
//Skip past the files to the log headers.
//

while (cRemainingBackupFiles--)
{
BackupFile bf = {0};

err = ErrReadHeader(hBackupFile, &bf);

if (err != ERROR_SUCCESS)
{
return(err);
}
LARGE_INTEGER liMoveDelta = {0};

liMoveDelta = bf.liFileSize;

liMoveDelta.QuadPart += bf.cbFileNameLength;

if (!SetFilePointer(hBackupFile, liMoveDelta.LowPart, &liMoveDelta.HighPart, FILE_CURRENT)) {
printf("Unable to set file pointer past file.\n");
return(1);
}
}

LogHeader lh = {0};

err = ErrReadHeader(hBackupFile, &lh);

if (err != ERROR_SUCCESS)
{
return(err);
}
//
//We now know the total number of logs to back up.
//

C cBackupFiles = lh.cLogFiles + bh.cBackupFiles;


printf("Restoring %s database\n", szRestoreAnnotation);

if (!SetFilePointer(hBackupFile, sizeof(BackupHeader)+bh.cbDatabaseNameLength, NULL, FILE_BEGIN)) {
printf("Unable to reset database pointer to start of database.\n");
return(1);
}

I irgRestMap = 0;
EDB_RSTMAP *rgRestMap=NULL;


//
//If cRemainingBackupFiles == 0 then we are doing an
//- incremental restore
//
cRemainingBackupFiles = bh.cBackupFiles;
if (cRemainingBackupFiles)
{
rgRestMap = new EDB_RSTMAP[cBackupFiles];
if (rgRestMap == NULL)
{
printf("Error allocating memory for restore map\n");
return(1);
}
}

//
//Now copy the restore database.
//

while (cRemainingBackupFiles--)
{
ERR err = ErrRestoreFile(hBackupFile, rgRestMap, &irgRestMap, szDatabaseLocationList);
if (err != ERROR_SUCCESS)
{
printf("Unable to restore file.\n");
return(err);
}
}

//
//Now read the log header again.
//
err = ErrReadHeader(hBackupFile, &lh);

cRemainingBackupFiles = lh.cLogFiles;

DWORD genLow = 0xffffffffL;
DWORD genHigh = 0;

SZ szBackupLogPath = NULL;

while (cRemainingBackupFiles--)
{
DWORD gen = 0;
BOOL fSetGen = fFalse;

ERR err = ErrRestoreFile(
hBackupFile,
rgRestMap,
&irgRestMap,
szDatabaseLocationList,
&szBackupLogPath,
&fSetGen,
&gen);
if (err != ERROR_SUCCESS)
{
printf("Unable to restore file.\n");
return(err);
}
if (fSetGen)
{
if (gen < genLow)
{
genLow = gen;
}

if (gen > genHigh)
{
genHigh = gen;
}
}
}

printf("Databases successfully restored\n");

SZ szLogPath = NULL;

SZ szCheckpointDir = NULL;

//
//Now find out where the database locations go.
//

SZ szDatabaseLocation = szDatabaseLocationList;

while (*szDatabaseLocation)
{
BFT bftLocation = *szDatabaseLocation++;
if (bftLocation == BFT_LOG_DIR)
{
szLogPath = szDatabaseLocation;
}
else if (bftLocation == BFT_CHECKPOINT_DIR)
{
szCheckpointDir = szDatabaseLocation;
}
else

szDatabaseLocation += strlen(szDatabaseLocation)+1;
}

err = HrRestoreRegister(hbc, szCheckpointDir, szLogPath, rgRestMap, irgRestMap, szBackupLogPath, genLow, genHigh);

if (err != ERROR_SUCCESS)
{
(void) HrRestoreRegisterComplete(hbc, err);
(void) HrRestoreEnd(hbc);
printf("Unable to perform restore %d\n", err);
return(err);
}

(void) HrRestoreRegisterComplete(hbc, hrNone);

err = HrRestoreEnd(hbc);

if (err != ERROR_SUCCESS)
{
printf("Unable to complete restore: %d\n", err);
return(err);
}

return(0);

}