|
|
/*++
� 1998 Seagate Software, Inc. All rights reserved.
Module Name:
Wsbdbsys.cpp
Abstract:
CWsbDbSys class.
Author:
Ron White [ronw] 1-Jul-1997
Revision History:
--*/
#include "stdafx.h"
#include "rsevents.h"
#include "wsbdbsys.h"
#include "wsbdbses.h"
#include <mbstring.h>
#include <limits.h>
#define MAX_ATTACHED_DB 6 // Set by ESE/JET engine (suppose to be 7)
#if !defined(BACKUP_TEST_TIMES)
// Normal values
#define DEFAULT_AUTOBACKUP_INTERVAL (3 * 60 * 60 * 1000) // 3 hours
#define DEFAULT_AUTOBACKUP_IDLE_MINUTES 5
#define DEFAULT_AUTOBACKUP_COUNT_MIN 100
#define DEFAULT_AUTOBACKUP_LOG_COUNT 10
#else
// Test values
#define DEFAULT_AUTOBACKUP_INTERVAL (4 * 60 * 1000) // 4 minutes
#define DEFAULT_AUTOBACKUP_IDLE_MINUTES 1
#define DEFAULT_AUTOBACKUP_COUNT_MIN 5
#define DEFAULT_AUTOBACKUP_LOG_COUNT 4
#endif
#define DEFAULT_AUTOBACKUP_COUNT_MAX 500
// Local stuff
// ATTACHED_DB_DATA holds information about currently attached DBs
typedef struct { CWsbStringPtr Name; // Database name
LONG LastOpen; // Sequence number of last open
} ATTACHED_DB_DATA;
// This static data manages a list of attached databases for this process.
// (Future: If we want this list to be managed on a per instance basis, all of
// this data should become class members and handled appropriately)
static ATTACHED_DB_DATA Attached[MAX_ATTACHED_DB]; static LONG AttachedCount = 0; static CRITICAL_SECTION AttachedCritSect; static BOOL CritSectCreated = FALSE; static BOOL AttachedInit = FALSE; static SHORT AttachedCritSectUsers = 0;
static CComCreator< CComObject<CWsbDbSession> > SessionFactory;
// Local functions
static HRESULT AddExtension(OLECHAR** pPath, OLECHAR* Ext); static HRESULT ClearDirectory(const OLECHAR* DirPath); static HRESULT CopyDirectory(const OLECHAR* DirSource, const OLECHAR* DirTarget); static HRESULT DirectoryHasFullBackup(const OLECHAR* DirPath); static HRESULT FileCount(const OLECHAR* DirPath, const OLECHAR* Pattern, ULONG* Count); static HRESULT RenameDirectory(const OLECHAR* OldDir, const OLECHAR* NewDir);
// Non-member function initially called for autobackup thread
static DWORD WsbDbSysStartAutoBackup( void* pVoid ) { return(((CWsbDbSys*) pVoid)->AutoBackup()); }
HRESULT CWsbDbSys::AutoBackup( void )
/*++
Routine Description:
Implements an auto-backup loop.
Arguments:
None. Return Value:
Doesn't matter.
--*/ { HRESULT hr = S_OK;
try { ULONG SleepPeriod = DEFAULT_AUTOBACKUP_INTERVAL; BOOL exitLoop = FALSE;
while (! exitLoop) {
// Wait for termination event, if timeout occurs, check the sleep period criteria
switch (WaitForSingleObject(m_terminateEvent, SleepPeriod)) { case WAIT_OBJECT_0: // Need to terminate
WsbTrace(OLESTR("CWsbDbSys::AutoBackup: signaled to terminate\n")); exitLoop = TRUE; break;
case WAIT_TIMEOUT: // Check if backup need to be performed
WsbTrace(OLESTR("CWsbDbSys::AutoBackup awakened, ChangeCount = %ld\n"), m_ChangeCount);
// Don't do a backup if there hasn't been much activity
if (DEFAULT_AUTOBACKUP_COUNT_MIN < m_ChangeCount) { LONG DiffMinutes; FILETIME ftNow; LONGLONG NowMinutes; LONGLONG ThenMinutes;
// Wait for an idle time
GetSystemTimeAsFileTime(&ftNow); NowMinutes = WsbFTtoLL(ftNow) / WSB_FT_TICKS_PER_MINUTE; ThenMinutes = WsbFTtoLL(m_LastChange) / WSB_FT_TICKS_PER_MINUTE; DiffMinutes = static_cast<LONG>(NowMinutes - ThenMinutes);
WsbTrace(OLESTR("CWsbDbSys::AutoBackup idle minutes = %ld\n"), DiffMinutes); if (DEFAULT_AUTOBACKUP_IDLE_MINUTES < DiffMinutes || DEFAULT_AUTOBACKUP_COUNT_MAX < m_ChangeCount) { hr = Backup(NULL, 0); if (S_OK != hr) { // Just trace and go back to wait for the next round...
WsbTrace(OLESTR("CWsbDbSys::AutoBackup: Backup failed, hr=<%ls>\n"), WsbHrAsString(hr)); } SleepPeriod = DEFAULT_AUTOBACKUP_INTERVAL;; } else { // Reduce the sleep time so we catch the next idle time
ULONG SleepMinutes = SleepPeriod / (1000 * 60);
if (SleepMinutes > (DEFAULT_AUTOBACKUP_IDLE_MINUTES * 2)) { SleepPeriod /= 2; } } }
break; // end of timeout case
case WAIT_FAILED: default: WsbTrace(OLESTR("CWsbDbSys::AutoBackup: WaitForSingleObject returned error %lu\n"), GetLastError()); exitLoop = TRUE; break;
} // end of switch
} // end of while
} WsbCatch(hr);
return(hr); }
HRESULT CWsbDbSys::Backup( IN OLECHAR* path, IN ULONG flags )
/*++
Implements:
IWsbDbSys::Backup
--*/ { HRESULT hr = S_OK; char* backup_path = NULL;
WsbTraceIn(OLESTR("CWsbDbSys::Backup"), OLESTR("path = <%ls>, flags = %lx"), path, flags); try {
CWsbStringPtr BackupDir; JET_ERR jstat = JET_errSuccess;
WsbAffirm(m_jet_initialized, WSB_E_NOT_INITIALIZED);
// Set and save the backup path; make sure it exists
if (NULL != path) { m_BackupPath = path; } CreateDirectory(m_BackupPath, NULL);
// Start the automatic backup thread if requested
if (flags & IDB_BACKUP_FLAG_AUTO) {
// Don't start AutoBackup thread if it's already running
if (0 == m_AutoThread) { DWORD threadId;
// Create termination event for auto-backup thread
WsbAffirmHandle(m_terminateEvent = CreateEvent(NULL, TRUE, FALSE, NULL));
WsbAffirm((m_AutoThread = CreateThread(0, 0, WsbDbSysStartAutoBackup, (void*) this, 0, &threadId)) != 0, HRESULT_FROM_WIN32(GetLastError())); }
// Do a full backup to a temporary directory
} else if (flags & IDB_BACKUP_FLAG_FORCE_FULL) { BOOL UsedTempDir = FALSE;
// Don't wipe out an existing backup -- if the normal backup
// directory contains a full backup, do the full backup to
// the .ful directory
BackupDir = m_BackupPath; WsbAffirm(0 != (WCHAR *)BackupDir, E_OUTOFMEMORY); if (S_OK == DirectoryHasFullBackup(BackupDir)) { WsbAffirmHr(AddExtension(&BackupDir, L".ful")); UsedTempDir = TRUE; }
// Make sure the directory exists (should check for errors?)
CreateDirectory(BackupDir, NULL);
// Make sure the directory is empty (the call to JetBackup will
// fail if it's not)
WsbAffirmHr(ClearDirectory(BackupDir));
// Convert to narrow char string for parameter
WsbAffirmHr(wsb_db_jet_fix_path(BackupDir, NULL, &backup_path)); WsbTrace(OLESTR("CWsbDbSys::Backup: backup_path = <%hs>\n"), backup_path);
// Do backup
WsbAffirm(NULL != m_BackupEvent, WSB_E_IDB_WRONG_BACKUP_SETTINGS); DWORD status = WaitForSingleObject(m_BackupEvent, EVENT_WAIT_TIMEOUT); DWORD errWait; switch(status) { case WAIT_OBJECT_0: // Expected case - do Backup
jstat = JetBackupInstance(m_jet_instance, backup_path, 0, NULL); if (! SetEvent(m_BackupEvent)) { // Don't abort, just trace error
WsbTraceAlways(OLESTR("CWsbDbSys::Backup: SetEvent returned unexpected error %lu\n"), GetLastError()); } WsbAffirmHr(jet_error(jstat)); break;
case WAIT_TIMEOUT: // Timeout - don't do backup
WsbTraceAlways(OLESTR("CWsbDbSys::Backup, Wait for Single Object timed out after %lu ms\n"), EVENT_WAIT_TIMEOUT); WsbThrow(E_ABORT); break;
case WAIT_FAILED: errWait = GetLastError(); WsbTraceAlways(OLESTR("CWsbDbSys::Backup, Wait for Single Object returned error %lu\n"), errWait); WsbThrow(HRESULT_FROM_WIN32(errWait)); break;
default: WsbTraceAlways(OLESTR("CWsbDbSys::Backup, Wait for Single Object returned unexpected status %lu\n"), status); WsbThrow(E_UNEXPECTED); break; }
// Full backup worked -- copy to real backup directory
if (UsedTempDir) { try { WsbAffirmHr(ClearDirectory(m_BackupPath)); WsbAffirmHr(CopyDirectory(BackupDir, m_BackupPath)); WsbAffirmHr(ClearDirectory(BackupDir));
// Try to delete temporary directory (may fail)
DeleteFile(BackupDir); BackupDir = m_BackupPath; } WsbCatch(hr); } WsbLogEvent(WSB_MESSAGE_IDB_BACKUP_FULL, 0, NULL, WsbAbbreviatePath(BackupDir, 120), NULL); m_ChangeCount = 0; WsbAffirmHr(hr);
// Try an incremental backup
} else { ULONG LogCount; BOOL TryFullBackup = FALSE;
WsbAffirmHr(FileCount(m_BackupPath, L"*.log", &LogCount));
if (LogCount > DEFAULT_AUTOBACKUP_LOG_COUNT || S_FALSE == DirectoryHasFullBackup(m_BackupPath)) { // Do a full backup instead of the incremental if there
// are already too many log files, or there's no full
// backup in the backup directory (which means the incremental
// wouldn't work anyway)
TryFullBackup = TRUE; } else { WsbTrace(OLESTR("CWsbDbSys::Backup, trying incremental backup\n"));
// Convert to narrow char string for parameter
WsbAffirmHr(wsb_db_jet_fix_path(m_BackupPath, NULL, &backup_path)); WsbTrace(OLESTR("CWsbDbSys::Backup: backup_path = <%hs>\n"), backup_path);
WsbAffirm(NULL != m_BackupEvent, WSB_E_IDB_WRONG_BACKUP_SETTINGS); DWORD status = WaitForSingleObject(m_BackupEvent, EVENT_WAIT_TIMEOUT); DWORD errWait; switch(status) { case WAIT_OBJECT_0: // Expected case - do Backup
jstat = JetBackupInstance(m_jet_instance, backup_path, JET_bitBackupIncremental, NULL); if (! SetEvent(m_BackupEvent)) { // Don't abort, just trace error
WsbTraceAlways(OLESTR("CWsbDbSys::Backup: SetEvent returned unexpected error %lu\n"), GetLastError()); } break;
case WAIT_TIMEOUT: // Timeout - don't do backup
WsbTraceAlways(OLESTR("CWsbDbSys::Backup, Wait for Single Object timed out after %lu ms\n"), EVENT_WAIT_TIMEOUT); WsbThrow(E_ABORT); break;
case WAIT_FAILED: errWait = GetLastError(); WsbTraceAlways(OLESTR("CWsbDbSys::Backup, Wait for Single Object returned error %lu\n"), errWait); WsbThrow(HRESULT_FROM_WIN32(errWait)); break;
default: WsbTraceAlways(OLESTR("CWsbDbSys::Backup, Wait for Single Object returned unexpected status %lu\n"), status); WsbThrow(E_UNEXPECTED); break; }
// Check for an error.
if (JET_errSuccess != jstat) { if (JET_errMissingFullBackup == jstat) { // Full backup need to be performed
WsbLogEvent(WSB_MESSAGE_IDB_MISSING_FULL_BACKUP, 0, NULL, WsbAbbreviatePath(m_BackupPath, 120), NULL); } else { // Unknown error of incremental backup. Try a full backup anyway
WsbLogEvent(WSB_MESSAGE_IDB_INCREMENTAL_BACKUP_FAILED, 0, NULL, WsbAbbreviatePath(m_BackupPath, 120), WsbLongAsString(jstat), NULL ); } TryFullBackup = TRUE; } else { // The incremental backup worked
WsbLogEvent(WSB_MESSAGE_IDB_BACKUP_INCREMENTAL, 0, NULL, WsbAbbreviatePath(m_BackupPath, 120), NULL); m_ChangeCount = 0; } }
// Try full backup?
if (TryFullBackup) { WsbAffirmHr(Backup(NULL, IDB_BACKUP_FLAG_FORCE_FULL)); } }
} WsbCatchAndDo(hr, WsbLogEvent(WSB_MESSAGE_IDB_BACKUP_FAILED, 0, NULL, WsbAbbreviatePath(m_BackupPath, 120), NULL); );
if (NULL != backup_path) { WsbFree(backup_path); }
WsbTraceOut(OLESTR("CWsbDbSys::Backup"), OLESTR("hr =<%ls>"), WsbHrAsString(hr));
return(hr); }
HRESULT CWsbDbSys::FinalConstruct( void )
/*++
Implements:
CComObjectRoot::FinalConstruct
--*/ { HRESULT hr = S_OK;
WsbTraceIn(OLESTR("CWsbDbSys::FinalConstruct"), OLESTR("") );
try { m_AutoThread = 0; m_terminateEvent = NULL; m_ChangeCount = 0;
m_jet_initialized = FALSE; m_jet_instance = JET_instanceNil;
m_BackupEvent = NULL;
try { // Initialize critical sections (global resource, so init only for first user)
if (AttachedCritSectUsers == 0) { WsbAffirmStatus(InitializeCriticalSectionAndSpinCount (&AttachedCritSect, 1000)); CritSectCreated = TRUE; } AttachedCritSectUsers++; } catch(DWORD status) { AttachedCritSectUsers--; WsbLogEvent(status, 0, NULL, NULL); switch (status) { case STATUS_NO_MEMORY: WsbThrow(E_OUTOFMEMORY); break; default: WsbThrow(E_UNEXPECTED); break; } }
} WsbCatch(hr);
WsbTraceOut(OLESTR("CWsbDbSys::FinalConstruct"), OLESTR("hr =<%ls>"), WsbHrAsString(hr));
return(hr); }
void CWsbDbSys::FinalRelease( void )
/*++
Implements:
CComObjectRoot::FinalRelease
--*/ { HRESULT hr = S_OK;
WsbTraceIn(OLESTR("CWsbDbSys::FinalRelease"), OLESTR(""));
try { // Make sure that Terminate was called
if (m_jet_initialized == TRUE) { WsbAffirmHr(Terminate()); } } WsbCatch(hr);
// Global resource, so delete only for last user
AttachedCritSectUsers--; if ((AttachedCritSectUsers == 0) && CritSectCreated) { DeleteCriticalSection(&AttachedCritSect); }
WsbTraceOut(OLESTR("CWsbDbSys::FinalRelease"), OLESTR("hr =<%ls>"), WsbHrAsString(hr)); }
HRESULT CWsbDbSys::Init( IN OLECHAR* path, IN ULONG flags )
/*++
Implements:
IWsbDbSys::Init
--*/ { HRESULT hr = S_OK; char* log_path = NULL; static BOOL bFirstTime = TRUE; static int nInstance = 0;
WsbTraceIn(OLESTR("CWsbDbSys::Init"), OLESTR("path = <%ls>"), path); try {
CWsbStringPtr dir; JET_ERR jstat = JET_errSuccess;
// Initialize the Jet engine just once per Jet instance
WsbAffirm(!m_jet_initialized, E_FAIL);
// Initialize backup event, unless Jet backup is not required for this isntance
if (! (flags & IDB_SYS_INIT_FLAG_NO_BACKUP)) { // Event should already exist - it is created in the CRssJetWriter constructor
WsbAffirmHandle(m_BackupEvent = OpenEvent(EVENT_ALL_ACCESS, FALSE, HSM_IDB_STATE_EVENT)); }
// WsbDbSys represents one Jet instance.
// However, some Jet initialization should be done only once per process,
// before the first instance is being created.
if (bFirstTime) { bFirstTime = FALSE;
// Increase the default number of maximum Jet sesions for the process
// TEMPORARY: Can this be set separately per instance?
jstat = JetSetSystemParameter(0, 0, JET_paramCacheSizeMin , (IDB_MAX_NOF_SESSIONS*4), NULL); WsbTrace(OLESTR("CWsbDbSys::Init, JetSetSystemParameter(CacheSizeMax) = %ld\n"), jstat); WsbAffirmHr(jet_error(jstat)); jstat = JetSetSystemParameter(0, 0, JET_paramMaxSessions, IDB_MAX_NOF_SESSIONS, NULL); WsbTrace(OLESTR("CWsbDbSys::Init, JetSetSystemParameter(MaxSessions) = %ld\n"), jstat); WsbAffirmHr(jet_error(jstat));
// Tell Jet we are going to use multiple instances
jstat = JetEnableMultiInstance(NULL, 0, NULL); WsbAffirmHr(jet_error(jstat)); }
// Here start the per-instance initialization.
// First step is creating the instance
// Use a numeric counter as instance name - we care only that the name is unique
WsbAssert(JET_instanceNil == m_jet_instance, E_FAIL); nInstance++; char szInstance[10]; sprintf(szInstance, "%d", nInstance); WsbTrace(OLESTR("CWsbDbSys::Init, Jet instance name = <%hs>\n"), szInstance); jstat = JetCreateInstance(&m_jet_instance, szInstance); WsbAffirmHr(jet_error(jstat));
// Set some per-instance parameters:
// Create path for log directory (same path is also used for system files and temp files)
WsbAffirm(NULL != path, E_INVALIDARG); m_InitPath = path; m_BackupPath = m_InitPath; WsbAffirmHr(AddExtension(&m_BackupPath, L".bak")); WsbTrace(OLESTR("CWsbDbSys::Init, BackupPath = <%ls>\n"), (WCHAR *)m_BackupPath); WsbAffirmHr(wsb_db_jet_fix_path(path, OLESTR(""), &log_path)); dir = log_path; // Convert to WCHAR
// Make sure the directory exists.
WsbTrace(OLESTR("CWsbDbSys::Init, Creating dir = <%ls>\n"), (WCHAR *)dir); if (! CreateDirectory(dir, NULL)) { DWORD status = GetLastError(); if ((status == ERROR_ALREADY_EXISTS) || (status == ERROR_FILE_EXISTS)) { status = NO_ERROR; } WsbAffirmNoError(status); }
ULONG checkpointDepth; ULONG logFileSize = 128; // In kilobytes
if (! (flags & IDB_SYS_INIT_FLAG_NO_LOGGING)) {
WsbTrace(OLESTR("CWsbDbSys::Init, LogFilePath = <%hs>\n"), log_path); jstat = JetSetSystemParameter(&m_jet_instance, 0, JET_paramLogFilePath, 0, log_path); WsbTrace(OLESTR("CWsbDbSys::Init, JetSetSystemParameter(LogFilePath) = %ld\n"), jstat); WsbAffirmHr(jet_error(jstat));
// Use circular logging for "limited" logging
if (flags & IDB_SYS_INIT_FLAG_LIMITED_LOGGING) { logFileSize = 512; // Increase the log file size
jstat = JetSetSystemParameter(&m_jet_instance, 0, JET_paramCircularLog, 1, NULL); WsbAffirmHr(jet_error(jstat)); WsbTrace(OLESTR("CWsbDbSys::Init: set circular logging\n"));
// Set the amount of logging allowed before a check point
// to allow about 4 log files
// (the check point depth is set in bytes.)
checkpointDepth = 4 * logFileSize * 1024; jstat = JetSetSystemParameter(&m_jet_instance, 0, JET_paramCheckpointDepthMax, checkpointDepth, NULL); WsbAffirmHr(jet_error(jstat)); WsbTrace(OLESTR("CWsbDbSys::Init: set CheckpointDepthMax = %ld\n"), checkpointDepth); }
} else { jstat = JetSetSystemParameter(&m_jet_instance, 0, JET_paramRecovery, 0, "off"); WsbAffirmHr(jet_error(jstat)); WsbTrace(OLESTR("CWsbDbSys::Init: set JET_paramRecovery to 0 (no logging)\n")); }
// Set parameters for where to put auxiliary data
WsbTrace(OLESTR("CWsbDbSys::Init, SystemPath = <%hs>\n"), log_path); jstat = JetSetSystemParameter(&m_jet_instance, 0, JET_paramSystemPath, 0, log_path); WsbAffirmHr(jet_error(jstat));
// The next one, for some unknown reason, needs a file name at the end of the path
WsbAffirmHr(dir.Append("\\temp.edb")); WsbAffirmHr(dir.CopyTo(&log_path)); WsbTrace(OLESTR("CWsbDbSys::Init, TempPath = <%hs>\n"), log_path); jstat = JetSetSystemParameter(&m_jet_instance, 0, JET_paramTempPath, 0, log_path); WsbAffirmHr(jet_error(jstat));
if (! (flags & IDB_SYS_INIT_FLAG_NO_LOGGING)) {
// Set the log file size (in KB). The minimum seems to be 128KB.
jstat = JetSetSystemParameter(&m_jet_instance, 0, JET_paramLogFileSize, logFileSize, NULL); WsbAffirmHr(jet_error(jstat)); WsbTrace(OLESTR("CWsbDbSys::Init: set logFileSize to %ld Kb\n"), logFileSize); }
// Set parameter for deleting out-of-range log files.
// These files may exist after a restore from a db backup without clearing the db directory first
if (! (flags & IDB_SYS_INIT_FLAG_NO_BACKUP)) { jstat = JetSetSystemParameter(&m_jet_instance, 0, JET_paramDeleteOutOfRangeLogs, 1, NULL); WsbAffirmHr(jet_error(jstat)); WsbTrace(OLESTR("CWsbDbSys::Init: set delete out-of-range logs\n")); }
// Initialize the DB instance
jstat = JetInit(&m_jet_instance); hr = jet_error(jstat);
// If this failed, report the error
if (!SUCCEEDED(hr)) { if (flags & IDB_SYS_INIT_FLAG_SPECIAL_ERROR_MSG) { // Special message for FSA
WsbLogEvent(WSB_E_IDB_DELETABLE_DATABASE_CORRUPT, 0, NULL, NULL); WsbThrow(WSB_E_RESOURCE_UNAVAILABLE); } else { WsbThrow(hr); } } WsbTrace(OLESTR("CWsbDbSys::Init: jet instance = %p\n"), (LONG_PTR)m_jet_instance); m_jet_initialized = TRUE;
// Create a session for internal use of this instance
WsbAffirmHr(NewSession(&m_pWsbDbSession)); WsbTrace(OLESTR("CWsbDbSys::Init, m_pWsbDbSession = %p\n"), (IWsbDbSession*)m_pWsbDbSession);
} WsbCatchAndDo(hr, WsbLogEvent(WSB_MESSAGE_IDB_INIT_FAILED, 0, NULL, WsbAbbreviatePath(m_InitPath, 120), NULL); );
if (NULL != log_path) { WsbFree(log_path); }
WsbTraceOut(OLESTR("CWsbDbSys::Init"), OLESTR("hr =<%ls>"), WsbHrAsString(hr));
return(hr); }
HRESULT CWsbDbSys::Terminate( void )
/*++
Implements:
IWsbDbSys::Terminate
--*/ { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CWsbDbSys::Terminate"), OLESTR(""));
try { // If wasn't initialized or alreday cleaned up - just get out
if (m_jet_initialized == FALSE) { WsbTrace(OLESTR("CWsbDbSys::Terminate - this insatnce is not initialized")); WsbThrow(S_OK); }
// Terminate the auto-backup thread
if (m_AutoThread) { // Signal thread to terminate
SetEvent(m_terminateEvent);
// Wait for the thread, if it doesn't terminate gracefully - kill it
switch (WaitForSingleObject(m_AutoThread, 20000)) { case WAIT_FAILED: { WsbTrace(OLESTR("CWsbDbSys::Terminate: WaitForSingleObject returned error %lu\n"), GetLastError()); } // fall through...
case WAIT_TIMEOUT: { WsbTrace(OLESTR("CWsbDbSys::Terminate: force terminating of auto-backup thread.\n"));
DWORD dwExitCode; if (GetExitCodeThread( m_AutoThread, &dwExitCode)) { if (dwExitCode == STILL_ACTIVE) { // thread still active
if (!TerminateThread (m_AutoThread, 0)) { WsbTrace(OLESTR("CWsbDbSys::Terminate: TerminateThread returned error %lu\n"), GetLastError()); } } } else { WsbTrace(OLESTR("CWsbDbSys::Terminate: GetExitCodeThread returned error %lu\n"), GetLastError()); }
break; }
default: // Thread terminated gracefully
break; }
// Best effort done for terminating auto-backup thread
CloseHandle(m_AutoThread); m_AutoThread = 0; } if (m_terminateEvent != NULL) { CloseHandle(m_terminateEvent); m_terminateEvent = NULL; }
// Detach DBs before exiting so they don't automatically get
// reattached the next time we start up
if (m_pWsbDbSession) { JET_SESID sid;
CComQIPtr<IWsbDbSessionPriv, &IID_IWsbDbSessionPriv> pSessionPriv = m_pWsbDbSession; WsbAffirmPointer(pSessionPriv); WsbAffirmHr(pSessionPriv->GetJetId(&sid));
// Clean up the Attached data
if (AttachedInit) { EnterCriticalSection(&AttachedCritSect); for (int i = 0; i < MAX_ATTACHED_DB; i++) { Attached[i].Name.Free(); Attached[i].LastOpen = 0; } JetDetachDatabase(sid, NULL); AttachedInit = FALSE; LeaveCriticalSection(&AttachedCritSect); }
// Release the global session for this instance
m_pWsbDbSession = 0; }
// Terminate Jet
JetTerm(m_jet_instance); m_jet_initialized = FALSE; m_jet_instance = JET_instanceNil;
} WsbCatch(hr);
if (m_BackupEvent) { CloseHandle(m_BackupEvent); m_BackupEvent = NULL; }
WsbTraceOut(OLESTR("CWsbDbSys::Terminate"), OLESTR("hr =<%ls>"), WsbHrAsString(hr));
return (hr); }
HRESULT CWsbDbSys::NewSession( OUT IWsbDbSession** ppSession )
/*++
Implements:
IWsbDbSys::NewSession
--*/ { HRESULT hr = S_OK;
WsbTraceIn(OLESTR("CWsbDbSys::NewSession"), OLESTR("")); try { WsbAffirm(0 != ppSession, E_POINTER); WsbAffirmHr(SessionFactory.CreateInstance(NULL, IID_IWsbDbSession, (void**)ppSession));
CComQIPtr<IWsbDbSessionPriv, &IID_IWsbDbSessionPriv> pSessionPriv = *ppSession; WsbAffirmPointer(pSessionPriv); WsbAffirmHr(pSessionPriv->Init(&m_jet_instance));
} WsbCatch(hr); WsbTraceOut(OLESTR("CWsbDbSys::NewSession"), OLESTR("hr =<%ls>"), WsbHrAsString(hr));
return(hr); }
HRESULT CWsbDbSys::GetGlobalSession( OUT IWsbDbSession** ppSession ) /*++
Implements:
IWsbDbSys::GetGlobalSession
--*/ { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CWsbDbSys::GetGlobalSession"), OLESTR(""));
//
// If the Task Manager has been created, return the pointer. Otherwise,
// fail.
try { WsbAssert(0 != ppSession, E_POINTER); *ppSession = m_pWsbDbSession; WsbAffirm(m_pWsbDbSession != 0, E_FAIL); m_pWsbDbSession.p->AddRef(); } WsbCatch(hr);
WsbTraceOut(OLESTR("CWsbDbSys::GetGlobalSession"), OLESTR("hr =<%ls>"), WsbHrAsString(hr)); return (hr); }
HRESULT CWsbDbSys::Restore( IN OLECHAR* fromPath, IN OLECHAR* toPath )
/*++
Implements:
IWsbDbSys::Restore
--*/ { HRESULT hr = S_OK; char* backup_path = NULL; char* restore_path = NULL;
WsbTraceIn(OLESTR("CWsbDbSys::Restore"), OLESTR("fromPath = <%ls>, toPath = <%ls>"), fromPath, toPath); try {
CWsbStringPtr dir; JET_ERR jstat;
// This is only allowed before Init
WsbAffirm(!m_jet_initialized, E_UNEXPECTED); WsbAffirm(NULL != fromPath, E_POINTER); WsbAffirm(NULL != toPath, E_POINTER);
// Convert pathes
WsbAffirmHr(wsb_db_jet_fix_path(fromPath, OLESTR(""), &backup_path)); WsbAffirmHr(wsb_db_jet_fix_path(toPath, OLESTR(""), &restore_path));
// Make sure the target directory exists. Should check for error.
dir = restore_path; CreateDirectory(dir, NULL);
jstat = JetRestoreInstance(m_jet_instance, backup_path, restore_path, NULL); WsbAffirmHr(jet_error(jstat));
} WsbCatch(hr);
if (NULL != backup_path) { WsbFree(backup_path); } if (NULL != restore_path) { WsbFree(restore_path); }
WsbTraceOut(OLESTR("CWsbDbSys::Restore"), OLESTR("hr =<%ls>"), WsbHrAsString(hr));
return(hr); }
HRESULT CWsbDbSys::IncrementChangeCount( void )
/*++
Implements:
IWsbDbSysPriv::IncrementChangeCount
Routine Description:
Increments the write count used by AutoBackup.
Arguments:
None. Return Value:
S_OK
--*/ {
HRESULT hr = S_OK;
WsbTraceIn(OLESTR("CWsbDbSys::IncrementChangeCount"), OLESTR("count = %ld"), m_ChangeCount);
try { m_ChangeCount++; GetSystemTimeAsFileTime(&m_LastChange); } WsbCatch(hr);
WsbTraceOut(OLESTR("CWsbDbSys::IncrementChangeCount"), OLESTR("count = %ld"), m_ChangeCount);
return(hr); }
HRESULT CWsbDbSys::DbAttachedAdd( OLECHAR* name, BOOL attach) /*++
Implements:
IWsbDbSysPriv::DbAttachedAdd
Routine Description:
Make sure DB is attached and update the last-used count.
--*/ { HRESULT hr = S_OK; char* jet_name = NULL;
WsbTraceIn(OLESTR("CWsbDbSys::DbAttachedAdd"), OLESTR("name = %ls, attach = %ls"), name, WsbBoolAsString(attach));
try { int i; int i_empty = -1; int i_found = -1; LONG min_count = AttachedCount + 1; CWsbStringPtr match_name;
WsbAssert(name, E_POINTER);
// Make sure the list is initialized
if (!AttachedInit) { WsbAffirmHr(DbAttachedInit()); }
// Convert the name
WsbAffirmHr(wsb_db_jet_fix_path(name, L"." IDB_DB_FILE_SUFFIX, &jet_name)); match_name = jet_name;
// See if it's already in the list; look for an empty slot; find the
// least-recently used DB
EnterCriticalSection(&AttachedCritSect); for (i = 0; i < MAX_ATTACHED_DB; i++) {
// Empty slot?
if (!Attached[i].Name) { if (-1 == i_empty) { // Save the first one found
i_empty = i; } } else {
// Gather some data for later
if (Attached[i].LastOpen < min_count) { min_count = Attached[i].LastOpen; }
// Already in list?
if (match_name.IsEqual(Attached[i].Name)) { i_found = i; } } }
// Make sure the count isn't going to overflow
if (LONG_MAX == AttachedCount + 1) { WsbAffirm(0 < min_count, E_FAIL);
// Adjust counts down to avoid overflow
for (i = 0; i < MAX_ATTACHED_DB; i++) { if (min_count <= Attached[i].LastOpen) { Attached[i].LastOpen -= min_count; } } AttachedCount -= min_count; } AttachedCount++;
// If it's already in the list, update the info
if (-1 != i_found) { WsbTrace(OLESTR("CWsbDbSys::DbAttachedAdd: i_found = %d\n"), i_found); Attached[i_found].LastOpen = AttachedCount;
// If there's an empty slot, use it
} else if (-1 != i_empty) { WsbTrace(OLESTR("CWsbDbSys::DbAttachedAdd: i_empty = %d\n"), i_empty); if (attach) { JET_ERR jstat; JET_SESID sid;
WsbAffirm(m_pWsbDbSession, WSB_E_NOT_INITIALIZED); CComQIPtr<IWsbDbSessionPriv, &IID_IWsbDbSessionPriv> pSessionPriv = m_pWsbDbSession; WsbAffirmPointer(pSessionPriv); WsbAffirmHr(pSessionPriv->GetJetId(&sid));
jstat = JetAttachDatabase(sid, jet_name, 0); if (JET_errFileNotFound == jstat) { WsbThrow(STG_E_FILENOTFOUND); } else if (JET_wrnDatabaseAttached == jstat) { WsbTrace(OLESTR("CWsbDbSys::DbAttachedAdd: DB is already attached\n")); // No problem
} else { WsbAffirmHr(jet_error(jstat)); } } Attached[i_empty].Name = match_name; Attached[i_empty].LastOpen = AttachedCount;
// Try to detach the oldest DB first
} else { WsbAffirmHr(DbAttachedEmptySlot()); WsbAffirmHr(DbAttachedAdd(name, attach)); } } WsbCatch(hr);
if (jet_name) { WsbFree(jet_name); } LeaveCriticalSection(&AttachedCritSect);
WsbTraceOut(OLESTR("CWsbDbSys::DbAttachedAdd"), OLESTR("hr =<%ls>"), WsbHrAsString(hr)); return(hr); }
HRESULT CWsbDbSys::DbAttachedEmptySlot( void) /*++
Implements:
IWsbDbSysPriv::DbAttachedEmptySlot
Routine Description:
Force an empty slot in the attached list even if this means detaching a DB.
--*/ { HRESULT hr = S_OK;
WsbTraceIn(OLESTR("CWsbDbSys::DbAttachedEmptySlot"), OLESTR(""));
// Don't worry about it if we're not initialized yet --
// all the slots are empty
if (AttachedInit) { EnterCriticalSection(&AttachedCritSect);
try { BOOL has_empty = FALSE; int i; int i_oldest; LONG oldest_count;
// Find an empty slot or the oldest that is not currently open
reloop: i_oldest = -1; oldest_count = AttachedCount; for (i = 0; i < MAX_ATTACHED_DB; i++) { if (!Attached[i].Name) { has_empty = TRUE; break; } else if (Attached[i].LastOpen < oldest_count) { i_oldest = i; oldest_count = Attached[i].LastOpen; } }
// If there's no empty slot, try detaching the oldest
WsbTrace(OLESTR("CWsbDbSys::DbAttachedEmptySlot: has_empty = %ls, i = %d, i_oldest = %d\n"), WsbBoolAsString(has_empty), i, i_oldest); if (!has_empty) { JET_ERR jstat; char* name; JET_SESID sid;
WsbAffirm(m_pWsbDbSession, WSB_E_NOT_INITIALIZED); CComQIPtr<IWsbDbSessionPriv, &IID_IWsbDbSessionPriv> pSessionPriv = m_pWsbDbSession; WsbAffirmPointer(pSessionPriv); WsbAffirmHr(pSessionPriv->GetJetId(&sid));
WsbAffirm(-1 != i_oldest, WSB_E_IDB_TOO_MANY_DB); WsbAffirmHr(wsb_db_jet_fix_path(Attached[i_oldest].Name, L"." IDB_DB_FILE_SUFFIX, &name)); jstat = JetDetachDatabase(sid, name); WsbFree(name); WsbTrace(OLESTR("CWsbDbSys::DbAttachedEmptySlot: JetDetachDatabase = %ld\n"), (LONG)jstat); if (JET_errDatabaseInUse == jstat) { WsbTrace(OLESTR("CWsbDbSys::DbAttachedEmptySlot: DB in use; try again\n")); Attached[i_oldest].LastOpen = AttachedCount; goto reloop; } else if (JET_errDatabaseNotFound != jstat) { WsbAffirmHr(jet_error(jstat)); } Attached[i_oldest].Name.Free(); Attached[i_oldest].LastOpen = 0; } } WsbCatch(hr); LeaveCriticalSection(&AttachedCritSect); }
WsbTraceOut(OLESTR("CWsbDbSys::DbAttachedEmptySlot"), OLESTR("hr =<%ls>"), WsbHrAsString(hr)); return(hr); }
HRESULT CWsbDbSys::DbAttachedInit( void) /*++
Implements:
IWsbDbSysPriv::DbAttachedInit
Routine Description:
Initialize the attached-DB-list data.
--*/ { HRESULT hr = S_OK;
WsbTraceIn(OLESTR("CWsbDbSys::DbAttachedInit"), OLESTR(""));
EnterCriticalSection(&AttachedCritSect);
try { if (!AttachedInit) { ULONG actual = 0; int i; JET_ERR jstat; JET_SESID sid;
WsbAffirm(m_pWsbDbSession, WSB_E_NOT_INITIALIZED); CComQIPtr<IWsbDbSessionPriv, &IID_IWsbDbSessionPriv> pSessionPriv = m_pWsbDbSession; WsbAffirmPointer(pSessionPriv); WsbAffirmHr(pSessionPriv->GetJetId(&sid));
// Initialize data
for (i = 0; i < MAX_ATTACHED_DB; i++) { Attached[i].Name.Free(); Attached[i].LastOpen = 0; }
// Make sure there aren't pre-attached DBs
jstat = JetDetachDatabase(sid, NULL); WsbTrace(OLESTR("CWsbDbSys::DbAttachedInit: JetDetachDatabase(NULL) = %ld\n"), (LONG)jstat); WsbAffirmHr(jet_error(jstat));
AttachedInit = TRUE; } } WsbCatch(hr);
LeaveCriticalSection(&AttachedCritSect);
WsbTraceOut(OLESTR("CWsbDbSys::DbAttachedInit"), OLESTR("hr =<%ls>"), WsbHrAsString(hr)); return(hr); }
HRESULT CWsbDbSys::DbAttachedRemove( OLECHAR* name) /*++
Implements:
IWsbDbSysPriv::DbAttachedRemove
Routine Description:
Detach a DB (if attached).
--*/ { HRESULT hr = S_FALSE; char* jet_name = NULL;
WsbTraceIn(OLESTR("CWsbDbSys::DbAttachedRemove"), OLESTR("name = %ls"), name);
try { int i; CWsbStringPtr match_name;
WsbAssert(name, E_POINTER); WsbAffirm(AttachedInit, S_FALSE);
// Convert the name
WsbAffirmHr(wsb_db_jet_fix_path(name, L"." IDB_DB_FILE_SUFFIX, &jet_name)); match_name = jet_name;
// See if it's in the list
EnterCriticalSection(&AttachedCritSect); for (i = 0; i < MAX_ATTACHED_DB; i++) { if (Attached[i].Name) { if (match_name.IsEqual(Attached[i].Name)) { JET_ERR jstat; JET_SESID sid;
WsbTrace(OLESTR("CWsbDbSys::DbAttachedRemove: found DB, index = %d\n"), i); WsbAffirm(m_pWsbDbSession, WSB_E_NOT_INITIALIZED); CComQIPtr<IWsbDbSessionPriv, &IID_IWsbDbSessionPriv> pSessionPriv = m_pWsbDbSession; WsbAffirmPointer(pSessionPriv); WsbAffirmHr(pSessionPriv->GetJetId(&sid));
jstat = JetDetachDatabase(sid, jet_name); WsbTrace(OLESTR("CWsbDbSys::DbAttachedRemove: JetDetachDatabase = %ld\n"), (LONG)jstat); if (JET_errDatabaseNotFound != jstat) { WsbAffirmHr(jet_error(jstat)); hr = S_OK; } Attached[i].Name.Free(); Attached[i].LastOpen = 0; break; } } } } WsbCatch(hr);
if (jet_name) { WsbFree(jet_name); } LeaveCriticalSection(&AttachedCritSect);
WsbTraceOut(OLESTR("CWsbDbSys::DbAttachedRemove"), OLESTR("hr =<%ls>"), WsbHrAsString(hr)); return(hr); }
// wsb_db_jet_check_error - check for a jet error; return S_OK for no error;
// print error to trace otherwise
HRESULT wsb_db_jet_check_error(LONG jstat, char *fileName, DWORD lineNo) { HRESULT hr = S_OK;
if (jstat != JET_errSuccess) { WsbTrace(OLESTR("Jet error = %ld (%hs line %ld)\n"), jstat, fileName, lineNo);
// Convert JET error to IDB error for some common values
switch (jstat) { case JET_errDiskFull: case JET_errLogDiskFull: hr = WSB_E_IDB_DISK_FULL; break; case JET_errDatabaseNotFound: hr = WSB_E_IDB_FILE_NOT_FOUND; break; case JET_errDatabaseInconsistent: case JET_errPageNotInitialized: case JET_errReadVerifyFailure: case JET_errDatabaseCorrupted: case JET_errBadLogSignature: case JET_errBadDbSignature: case JET_errBadCheckpointSignature: case JET_errCheckpointCorrupt: case JET_errMissingPatchPage: case JET_errBadPatchPage: hr = WSB_E_IDB_DATABASE_CORRUPT; break; case JET_errWriteConflict: hr = WSB_E_IDB_UPDATE_CONFLICT; break; default: hr = WSB_E_IDB_IMP_ERROR; break; }
// Log this error in the event log
if (g_WsbLogLevel) { CWsbStringPtr str;
WsbSetEventInfo(fileName, lineNo, VER_PRODUCTBUILD, RS_BUILD_VERSION); \ str = WsbLongAsString(jstat); if (WSB_E_IDB_IMP_ERROR != hr) { str.Prepend(" ("); str.Prepend(WsbHrAsString(hr)); str.Append(")"); } WsbTraceAndLogEvent(WSB_MESSAGE_IDB_ERROR, 0, NULL, static_cast<OLECHAR *>(str), NULL); } } return(hr); }
// wsb_db_jet_fix_path - convert database path name from OLESTR to char*,
// change (or add) extension.
// Returns HRESULT
//
// NOTE: OLECHAR* is passed in, but char* is returned
HRESULT wsb_db_jet_fix_path(OLECHAR* path, OLECHAR* ext, char** new_path) { HRESULT hr = S_OK;
try { CWsbStringPtr string; int tlen;
WsbAssertPointer(path); WsbAssertPointer(new_path);
// Add extension if given
string = path; WsbAffirm(0 != (WCHAR *)string, E_OUTOFMEMORY); if (ext) { WsbAffirmHr(AddExtension(&string, ext)); }
// Allocate char string
tlen = (wcslen(string) + 1) * sizeof(OLECHAR); *new_path = (char*)WsbAlloc(tlen); WsbAffirm(*new_path, E_OUTOFMEMORY);
// Convert from wide char to char
if (wcstombs(*new_path, string, tlen) == (size_t)-1) { WsbFree(*new_path); *new_path = NULL; WsbThrow(WSB_E_STRING_CONVERSION); } } WsbCatch(hr);
return(hr); }
// Local functions
// AddExtension - add (or replace) the file extension to the path.
// If Ext is NULL, remove the existing extension.
//
// Return S_OK if no errors occurred.
static HRESULT AddExtension(OLECHAR** pPath, OLECHAR* Ext) { HRESULT hr = S_OK;
WsbTraceIn(OLESTR("AddExtension(wsbdbsys)"), OLESTR("Path = \"%ls\", Ext = \"%ls\""), WsbAbbreviatePath(*pPath, 120), Ext );
try { int elen; int len; OLECHAR* new_path; OLECHAR* pc; OLECHAR* pc2; int tlen;
WsbAssertPointer(pPath); WsbAssertPointer(*pPath);
// Allocate string and copy path
len = wcslen(*pPath); if (Ext) { elen = wcslen(Ext); } else { elen = 0; } tlen = (len + elen + 1) * sizeof(OLECHAR); new_path = static_cast<OLECHAR*>(WsbAlloc(tlen)); WsbAffirm(new_path, E_OUTOFMEMORY); wcscpy(new_path, *pPath);
// Remove old extension (if there)
pc = wcsrchr(new_path, L'.'); pc2 = wcsrchr(new_path, L'\\'); if (pc && (!pc2 || pc2 < pc)) { *pc = L'\0'; }
// Add the new extension (if given)
if (Ext) { wcscat(new_path, Ext); }
// Return the new path
WsbFree(*pPath); *pPath = new_path; } WsbCatch(hr);
WsbTraceOut(OLESTR("AddExtension(wsbdbsys)"), OLESTR("hr =<%ls>, new path = \"%ls\""), WsbHrAsString(hr), WsbAbbreviatePath(*pPath, 120));
return(hr); }
// ClearDirectory - delete all files in a directory
// Return S_OK if no errors occurred.
static HRESULT ClearDirectory(const OLECHAR* DirPath) { DWORD err; WIN32_FIND_DATA FindData; HANDLE hFind = 0; HRESULT hr = S_OK; int nDeleted = 0; int nSkipped = 0; CWsbStringPtr SearchPath;
WsbTraceIn(OLESTR("ClearDirectory(wsbdbsys)"), OLESTR("Path = <%ls>"), WsbAbbreviatePath(DirPath, 120));
try { SearchPath = DirPath; SearchPath.Append("\\*");
hFind = FindFirstFile(SearchPath, &FindData); if (INVALID_HANDLE_VALUE == hFind) { hFind = 0; err = GetLastError(); WsbTrace(OLESTR("ClearDirectory(wsbdbsys): FindFirstFile(%ls) failed, error = %ld\n"), static_cast<OLECHAR*>(SearchPath), err); WsbThrow(HRESULT_FROM_WIN32(err)); }
while (TRUE) {
if (FindData.dwFileAttributes & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_HIDDEN)) { nSkipped++; } else { CWsbStringPtr DeletePath;
DeletePath = DirPath; DeletePath.Append("\\"); DeletePath.Append(FindData.cFileName); if (!DeleteFile(DeletePath)) { err = GetLastError(); WsbTrace(OLESTR("ClearDirectory(wsbdbsys): DeleteFile(%ls) failed, error = %ld\n"), static_cast<OLECHAR*>(DeletePath), err); WsbThrow(HRESULT_FROM_WIN32(err)); } nDeleted++; } if (!FindNextFile(hFind, &FindData)) { err = GetLastError(); if (ERROR_NO_MORE_FILES == err) break; WsbTrace(OLESTR("ClearDirectory(wsbdbsys): FindNextFile failed, error = %ld\n"), err); WsbThrow(HRESULT_FROM_WIN32(err)); } } } WsbCatch(hr);
if (0 != hFind) { FindClose(hFind); }
WsbTraceOut(OLESTR("ClearDirectory(wsbdbsys)"), OLESTR("hr =<%ls>, # deleted = %d, # skipped = %d"), WsbHrAsString(hr), nDeleted, nSkipped);
return(hr); }
// CopyDirectory - copy files from one directory to another
// Return S_OK if no errors occurred.
static HRESULT CopyDirectory(const OLECHAR* DirSource, const OLECHAR* DirTarget) { DWORD err; WIN32_FIND_DATA FindData; HANDLE hFind = 0; HRESULT hr = S_OK; int nCopied = 0; int nSkipped = 0; CWsbStringPtr SearchPath;
WsbTraceIn(OLESTR("CopyDirectory(wsbdbsys)"), OLESTR("OldPath = \"%ls\", NewPath = \"%ls\""), WsbQuickString(WsbAbbreviatePath(DirSource, 120)), WsbQuickString(WsbAbbreviatePath(DirTarget, 120)));
try { SearchPath = DirSource; SearchPath.Append("\\*");
hFind = FindFirstFile(SearchPath, &FindData); if (INVALID_HANDLE_VALUE == hFind) { hFind = 0; err = GetLastError(); WsbTrace(OLESTR("ClearDirectory(wsbdbsys): FindFirstFile(%ls) failed, error = %ld\n"), static_cast<OLECHAR*>(SearchPath), err); WsbThrow(HRESULT_FROM_WIN32(err)); }
while (TRUE) {
if (FindData.dwFileAttributes & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_HIDDEN)) { nSkipped++; } else { CWsbStringPtr NewPath; CWsbStringPtr OldPath;
OldPath = DirSource; OldPath.Append("\\"); OldPath.Append(FindData.cFileName); NewPath = DirTarget; NewPath.Append("\\"); NewPath.Append(FindData.cFileName); if (!CopyFile(OldPath, NewPath, FALSE)) { err = GetLastError(); WsbTrace(OLESTR("ClearDirectory(wsbdbsys): CopyFile(%ls, %ls) failed, error = %ld\n"), static_cast<OLECHAR*>(OldPath), static_cast<OLECHAR*>(NewPath), err); WsbThrow(HRESULT_FROM_WIN32(err)); } nCopied++; } if (!FindNextFile(hFind, &FindData)) { err = GetLastError(); if (ERROR_NO_MORE_FILES == err) break; WsbTrace(OLESTR("ClearDirectory(wsbdbsys): FindNextFile failed, error = %ld\n"), err); WsbThrow(HRESULT_FROM_WIN32(err)); } } } WsbCatch(hr);
if (0 != hFind) { FindClose(hFind); }
WsbTraceOut(OLESTR("CopyDirectory(wsbdbsys)"), OLESTR("hr =<%ls>, copied = %ld, skipped = %ld"), WsbHrAsString(hr), nCopied, nSkipped);
return(hr); }
// DirectoryHasFullBackup - try to determine if the directory contains a full backup
// Return
// S_OK if it contains a full backup
// S_FALSE if it doesn't
// E_* on errors
//
// The technique use here is somewhat ad hoc since it expects the full backup
// filename to end in IDB_DB_FILE_SUFFIX
static HRESULT DirectoryHasFullBackup(const OLECHAR* DirPath) { HRESULT hr = S_OK;
WsbTraceIn(OLESTR("DirectoryHasFullBackup(wsbdbsys)"), OLESTR("Path = <%ls>"), WsbAbbreviatePath(DirPath, 120));
try { ULONG Count;
WsbAffirmHr(FileCount(DirPath, L"*." IDB_DB_FILE_SUFFIX, &Count)); if (0 == Count) { hr = S_FALSE; }
} WsbCatch(hr);
WsbTraceOut(OLESTR("DirectoryHasFullBackup(wsbdbsys)"), OLESTR("hr =<%ls>"), WsbHrAsString(hr));
return(hr); }
// FileCount - count all files in a directory matching a pattern. Skip
// directories and hidden files.
// Return S_OK if no errors occurred.
static HRESULT FileCount(const OLECHAR* DirPath, const OLECHAR* Pattern, ULONG* Count) { DWORD err; WIN32_FIND_DATA FindData; HANDLE hFind = 0; HRESULT hr = S_OK; int lCount = 0; int nSkipped = 0; CWsbStringPtr SearchPath;
WsbTraceIn(OLESTR("FileCount(wsbdbsys)"), OLESTR("Path = <%ls>"), WsbAbbreviatePath(DirPath, 120));
try { SearchPath = DirPath; SearchPath.Append("\\"); SearchPath.Append(Pattern); *Count = 0;
hFind = FindFirstFile(SearchPath, &FindData); if (INVALID_HANDLE_VALUE == hFind) { hFind = 0; err = GetLastError(); if (ERROR_FILE_NOT_FOUND == err) WsbThrow(S_OK); WsbTrace(OLESTR("FileCount(wsbdbsys): FindFirstFile(%ls) failed, error = %ld\n"), static_cast<OLECHAR*>(SearchPath), err); WsbThrow(HRESULT_FROM_WIN32(err)); }
while (TRUE) {
if (FindData.dwFileAttributes & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_HIDDEN)) { nSkipped++; } else { lCount++; } if (!FindNextFile(hFind, &FindData)) { err = GetLastError(); if (ERROR_NO_MORE_FILES == err) break; WsbTrace(OLESTR("FileCount(wsbdbsys): FindNextFile failed, error = %ld\n"), err); WsbThrow(HRESULT_FROM_WIN32(err)); } } } WsbCatch(hr);
if (0 != hFind) { FindClose(hFind); }
if (S_OK == hr) { *Count = lCount; }
WsbTraceOut(OLESTR("FileCount(wsbdbsys)"), OLESTR("hr =<%ls>, # skipped = %d, Count = %ld"), WsbHrAsString(hr), nSkipped, *Count);
return(hr); }
// RenameDirectory - rename a directory
// Return S_OK if no errors occurred.
static HRESULT RenameDirectory(const OLECHAR* OldDir, const OLECHAR* NewDir) { DWORD err; HRESULT hr = S_OK;
WsbTraceIn(OLESTR("RenameDirectory(wsbdbsys)"), OLESTR("OldPath = \"%ls\", NewPath = \"%ls\""), WsbQuickString(WsbAbbreviatePath(OldDir, 120)), WsbQuickString(WsbAbbreviatePath(NewDir, 120)));
try { if (!MoveFile(OldDir, NewDir)) { err = GetLastError(); WsbTrace(OLESTR("RenameDirectory(wsbdbsys): MoveFile failed, error = %ld\n"), err); WsbThrow(HRESULT_FROM_WIN32(err)); } } WsbCatch(hr);
WsbTraceOut(OLESTR("RenameDirectory(wsbdbsys)"), OLESTR("hr =<%ls>"), WsbHrAsString(hr));
return(hr); }
|