|
|
/*
* db.c - Twin database module. */
/* Headers
**********/
#include "project.h"
#pragma hdrstop
#include "stub.h"
/* Constants
************/
/* database header magic id string */
#define MAGIC_HEADER "DDSH\x02\x05\x01\x14"
/* length of MAGIC_HEADER (no null terminator) */
#define MAGIC_HEADER_LEN (8)
/* Types
********/
typedef struct _dbheader { BYTE rgbyteMagic[MAGIC_HEADER_LEN]; DWORD dwcbHeaderLen; DWORD dwMajorVer; DWORD dwMinorVer; } DBHEADER; DECLARE_STANDARD_TYPES(DBHEADER);
/***************************** Private Functions *****************************/
/* Module Prototypes
********************/
PRIVATE_CODE TWINRESULT WriteDBHeader(HCACHEDFILE, PDBHEADER); PRIVATE_CODE TWINRESULT ReadDBHeader(HCACHEDFILE, PDBHEADER); PRIVATE_CODE TWINRESULT CheckDBHeader(PCDBHEADER); PRIVATE_CODE TWINRESULT WriteTwinInfo(HCACHEDFILE, HBRFCASE); PRIVATE_CODE TWINRESULT ReadTwinInfo(HCACHEDFILE, HBRFCASE, PCDBVERSION);
#ifdef VSTF
PRIVATE_CODE BOOL IsValidPCDBHEADER(PCDBHEADER);
#endif
/*
** WriteDBHeader() ** ** ** ** Arguments: ** ** Returns: TWINRESULT ** ** Side Effects: none */ PRIVATE_CODE TWINRESULT WriteDBHeader(HCACHEDFILE hcf, PDBHEADER pdbh) { TWINRESULT tr;
ASSERT(IS_VALID_HANDLE(hcf, CACHEDFILE)); ASSERT(IS_VALID_STRUCT_PTR(pdbh, CDBHEADER));
if (WriteToCachedFile(hcf, (PCVOID)pdbh, sizeof(*pdbh), NULL)) tr = TR_SUCCESS; else tr = TR_BRIEFCASE_WRITE_FAILED;
return(tr); }
/*
** ReadDBHeader() ** ** ** ** Arguments: ** ** Returns: TWINRESULT ** ** Side Effects: none */ PRIVATE_CODE TWINRESULT ReadDBHeader(HCACHEDFILE hcf, PDBHEADER pdbh) { TWINRESULT tr; DWORD dwcbRead;
ASSERT(IS_VALID_HANDLE(hcf, CACHEDFILE)); ASSERT(IS_VALID_WRITE_PTR(pdbh, DBHEADER));
if (ReadFromCachedFile(hcf, pdbh, sizeof(*pdbh), &dwcbRead) && dwcbRead == sizeof(*pdbh)) tr = CheckDBHeader(pdbh); else tr = TR_CORRUPT_BRIEFCASE;
return(tr); }
/*
** CheckDBHeader() ** ** ** ** Arguments: ** ** Returns: TWINRESULT ** ** Side Effects: none */ PRIVATE_CODE TWINRESULT CheckDBHeader(PCDBHEADER pcdbh) { TWINRESULT tr = TR_CORRUPT_BRIEFCASE;
ASSERT(IS_VALID_READ_PTR(pcdbh, CDBHEADER));
if (MyMemComp(pcdbh->rgbyteMagic, MAGIC_HEADER, sizeof(pcdbh->rgbyteMagic)) == CR_EQUAL) { /* Treat older databases as corrupt. Support M8 databases. */
if (pcdbh->dwMajorVer == HEADER_MAJOR_VER && (pcdbh->dwMinorVer == HEADER_MINOR_VER || pcdbh->dwMinorVer == HEADER_M8_MINOR_VER)) { if (pcdbh->dwcbHeaderLen == sizeof(*pcdbh)) tr = TR_SUCCESS; } else if (pcdbh->dwMajorVer > HEADER_MAJOR_VER || (pcdbh->dwMajorVer == HEADER_MAJOR_VER && pcdbh->dwMinorVer > HEADER_MINOR_VER)) { tr = TR_NEWER_BRIEFCASE;
WARNING_OUT((TEXT("CheckDBHeader(): Newer database version %lu.%lu."), pcdbh->dwMajorVer, pcdbh->dwMinorVer)); } else { tr = TR_CORRUPT_BRIEFCASE;
WARNING_OUT((TEXT("CheckDBHeader(): Treating old database version %lu.%lu as corrupt. Current database version is %lu.%lu."), pcdbh->dwMajorVer, pcdbh->dwMinorVer, (DWORD)HEADER_MAJOR_VER, (DWORD)HEADER_MINOR_VER)); } }
return(tr); }
/*
** WriteTwinInfo() ** ** ** ** Arguments: ** ** Returns: TWINRESULT ** ** Side Effects: none */ PRIVATE_CODE TWINRESULT WriteTwinInfo(HCACHEDFILE hcf, HBRFCASE hbr) { TWINRESULT tr = TR_BRIEFCASE_WRITE_FAILED;
ASSERT(IS_VALID_HANDLE(hcf, CACHEDFILE)); ASSERT(IS_VALID_HANDLE(hbr, BRFCASE));
tr = WritePathList(hcf, GetBriefcasePathList(hbr));
if (tr == TR_SUCCESS) { tr = WriteBriefcaseInfo(hcf, hbr);
if (tr == TR_SUCCESS) { tr = WriteStringTable(hcf, GetBriefcaseNameStringTable(hbr));
if (tr == TR_SUCCESS) { tr = WriteTwinFamilies(hcf, GetBriefcaseTwinFamilyPtrArray(hbr));
if (tr == TR_SUCCESS) tr = WriteFolderPairList(hcf, GetBriefcaseFolderPairPtrArray(hbr)); } } }
return(tr); }
/*
** ReadTwinInfo() ** ** ** ** Arguments: ** ** Returns: TWINRESULT ** ** Side Effects: none */ PRIVATE_CODE TWINRESULT ReadTwinInfo(HCACHEDFILE hcf, HBRFCASE hbr, PCDBVERSION pcdbver) { TWINRESULT tr; HHANDLETRANS hhtPathTrans;
ASSERT(IS_VALID_HANDLE(hcf, CACHEDFILE)); ASSERT(IS_VALID_READ_PTR(pcdbver, DBVERSION)); ASSERT(IS_VALID_HANDLE(hbr, BRFCASE));
tr = ReadPathList(hcf, GetBriefcasePathList(hbr), &hhtPathTrans);
if (tr == TR_SUCCESS) { tr = ReadBriefcaseInfo(hcf, hbr, hhtPathTrans);
if (tr == TR_SUCCESS) { HHANDLETRANS hhtNameTrans;
tr = ReadStringTable(hcf, GetBriefcaseNameStringTable(hbr), &hhtNameTrans);
if (tr == TR_SUCCESS) { tr = ReadTwinFamilies(hcf, hbr, pcdbver, hhtPathTrans, hhtNameTrans);
if (tr == TR_SUCCESS) tr = ReadFolderPairList(hcf, hbr, hhtPathTrans, hhtNameTrans);
DestroyHandleTranslator(hhtNameTrans); } }
DestroyHandleTranslator(hhtPathTrans); }
return(tr); }
#ifdef VSTF
/*
** IsValidPCDBHEADER() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PRIVATE_CODE BOOL IsValidPCDBHEADER(PCDBHEADER pcdbh) { BOOL bResult;
if (IS_VALID_READ_PTR(pcdbh, CDBHEADER) && EVAL(MyMemComp(pcdbh->rgbyteMagic, MAGIC_HEADER, sizeof(pcbdh->rgbyteMagic)) == CR_EQUAL) && EVAL(pcdbh->dwcbHeaderLen == sizeof(*pcdbh)) && EVAL(pcdbh->dwMajorVer == HEADER_MAJOR_VER) && EVAL(pcdbh->dwMinorVer == HEADER_MINOR_VER || pcdbh->dwMinorVer == HEADER_M8_MINOR_VER)) bResult = TRUE; else bResult = FALSE;
return(bResult); }
#endif
/****************************** Public Functions *****************************/
/*
** WriteTwinDatabase() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE TWINRESULT WriteTwinDatabase(HCACHEDFILE hcf, HBRFCASE hbr) { TWINRESULT tr;
ASSERT(IS_VALID_HANDLE(hcf, CACHEDFILE)); ASSERT(IS_VALID_HANDLE(hbr, BRFCASE));
if (! SeekInCachedFile(hcf, 0, FILE_BEGIN)) { DBHEADER dbh;
/* Set up database header. */
CopyMemory(dbh.rgbyteMagic, MAGIC_HEADER, sizeof(dbh.rgbyteMagic)); dbh.dwcbHeaderLen = sizeof(dbh); dbh.dwMajorVer = HEADER_MAJOR_VER; dbh.dwMinorVer = HEADER_MINOR_VER;
tr = WriteDBHeader(hcf, &dbh);
if (tr == TR_SUCCESS) { TRACE_OUT((TEXT("WriteTwinDatabase(): Wrote database header version %lu.%lu."), dbh.dwMajorVer, dbh.dwMinorVer));
tr = WriteTwinInfo(hcf, hbr);
if (tr == TR_SUCCESS && ! SetEndOfCachedFile(hcf)) tr = TR_BRIEFCASE_WRITE_FAILED; } } else tr = TR_BRIEFCASE_WRITE_FAILED;
return(tr); }
/*
** ReadTwinDatabase() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE TWINRESULT ReadTwinDatabase(HBRFCASE hbr, HCACHEDFILE hcf) { TWINRESULT tr;
ASSERT(IS_VALID_HANDLE(hbr, BRFCASE)); ASSERT(IS_VALID_HANDLE(hcf, CACHEDFILE));
if (! SeekInCachedFile(hcf, 0, FILE_BEGIN)) { DBHEADER dbh;
tr = ReadDBHeader(hcf, &dbh);
if (tr == TR_SUCCESS) { TRACE_OUT((TEXT("ReadTwinDatabase(): Read database header version %lu.%lu."), dbh.dwMajorVer, dbh.dwMinorVer));
tr = ReadTwinInfo(hcf, hbr, (PCDBVERSION)&dbh.dwMajorVer);
if (tr == TR_SUCCESS) ASSERT(GetCachedFilePointerPosition(hcf) == GetCachedFileSize(hcf)); } } else tr = TR_BRIEFCASE_READ_FAILED;
return(tr); }
/*
** WriteDBSegmentHeader() ** ** ** ** Arguments: ** ** Returns: TWINRESULT ** ** Side Effects: none */ PUBLIC_CODE TWINRESULT WriteDBSegmentHeader(HCACHEDFILE hcf, LONG lcbDBSegmentHeaderOffset, PCVOID pcvSegmentHeader, UINT ucbSegmentHeaderLen) { TWINRESULT tr; DWORD dwcbStartOffset;
ASSERT(IS_VALID_HANDLE(hcf, CACHEDFILE)); ASSERT(lcbDBSegmentHeaderOffset >= 0); ASSERT(ucbSegmentHeaderLen > 0); ASSERT(IS_VALID_READ_BUFFER_PTR(pcvSegmentHeader, BYTE, ucbSegmentHeaderLen));
dwcbStartOffset = GetCachedFilePointerPosition(hcf);
if (dwcbStartOffset != INVALID_SEEK_POSITION && SeekInCachedFile(hcf, lcbDBSegmentHeaderOffset, SEEK_SET) != INVALID_SEEK_POSITION && WriteToCachedFile(hcf, pcvSegmentHeader, ucbSegmentHeaderLen, NULL) && SeekInCachedFile(hcf, dwcbStartOffset, SEEK_SET) != INVALID_SEEK_POSITION) tr = TR_SUCCESS; else tr = TR_BRIEFCASE_WRITE_FAILED;
return(tr); }
/*
** TranslateFCRESULTToTWINRESULT() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE TWINRESULT TranslateFCRESULTToTWINRESULT(FCRESULT fcr) { TWINRESULT tr;
switch (fcr) { case FCR_SUCCESS: tr = TR_SUCCESS; break;
case FCR_OUT_OF_MEMORY: tr = TR_OUT_OF_MEMORY; break;
case FCR_OPEN_FAILED: tr = TR_BRIEFCASE_OPEN_FAILED; break;
case FCR_CREATE_FAILED: tr = TR_BRIEFCASE_OPEN_FAILED; break;
case FCR_WRITE_FAILED: tr = TR_BRIEFCASE_WRITE_FAILED; break;
default: ASSERT(fcr == FCR_FILE_LOCKED); tr = TR_BRIEFCASE_LOCKED; break; }
return(tr); }
|