You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1829 lines
50 KiB
1829 lines
50 KiB
/******************************************************************************
|
|
*
|
|
* Copyright (c) 2000 Microsoft Corporation
|
|
*
|
|
* Module Name:
|
|
* datastor.cpp
|
|
*
|
|
* Abstract:
|
|
* CDataStore class functions
|
|
*
|
|
* Revision History:
|
|
* Brijesh Krishnaswami (brijeshk) 03/17/2000
|
|
* created
|
|
*
|
|
*****************************************************************************/
|
|
|
|
#include "datastor.h"
|
|
#include "datastormgr.h"
|
|
#include "enumlogs.h"
|
|
#include "srconfig.h"
|
|
#include "srapi.h"
|
|
#include "evthandler.h"
|
|
#include "..\snapshot\snappatch.h"
|
|
#include "NTServMsg.h" // generated from the MC message compiler
|
|
|
|
|
|
#ifdef THIS_FILE
|
|
#undef THIS_FILE
|
|
#endif
|
|
static char __szTraceSourceFile[] = __FILE__;
|
|
#define THIS_FILE __szTraceSourceFile
|
|
|
|
//
|
|
// The format for each line of the drive table
|
|
//
|
|
static WCHAR gs_wcsPrintFormat[] = L"%s/%s %x %i %i %s\r\n";
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: CDataStore::CDataStore
|
|
//
|
|
// Synopsis: Initialize an empty datastore object
|
|
//
|
|
// Arguments:
|
|
//
|
|
// History: 12-Apr-2000 HenryLee Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CDataStore::CDataStore (CDriveTable *pdt)
|
|
{
|
|
_pwszDrive[0] = L'\0';
|
|
_pwszGuid[0] = L'\0';
|
|
_pwszLabel[0] = L'\0';
|
|
_dwFlags = 0;
|
|
|
|
_llDataStoreUsageBytes = -1;
|
|
_llCurrentRpUsageBytes = 0;
|
|
_llDataStoreSizeBytes = 0;
|
|
_llDiskFreeBytes = 0;
|
|
|
|
_prp = NULL;
|
|
_prpe = NULL;
|
|
_iChangeLogs = -1;
|
|
_pdt = pdt;
|
|
}
|
|
|
|
CDataStore::~CDataStore()
|
|
{
|
|
if (_prp != NULL)
|
|
delete _prp;
|
|
|
|
if (_prpe != NULL)
|
|
delete _prpe;
|
|
|
|
// we leave _pdt as a dangling reference,
|
|
// since deleting _pdt will delete all child datastores
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: CDataStore::LoadDataStore
|
|
//
|
|
// Synopsis: Initialize a datastore object from a file
|
|
//
|
|
// Arguments: [pwszDrive] -- optional drive letter
|
|
// [pwszGuid] -- mount manager GUID
|
|
// [pwszLabel] -- optional volume label
|
|
// [dwFlags] -- SR volume flags
|
|
// [iChangeLogs] -- number of change logs
|
|
// [llSizeLimit] -- datastore size limit
|
|
//
|
|
// History: 12-Apr-2000 HenryLee Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
DWORD CDataStore::LoadDataStore (WCHAR *pwszDrive,
|
|
WCHAR *pwszGuid,
|
|
WCHAR *pwszLabel,
|
|
DWORD dwFlags,
|
|
int iChangeLogs,
|
|
INT64 llSizeLimit)
|
|
{
|
|
if (pwszDrive != NULL)
|
|
{
|
|
if (lstrlen(pwszDrive) >= MAX_PATH)
|
|
return ERROR_INVALID_PARAMETER;
|
|
else
|
|
lstrcpy (_pwszDrive, pwszDrive);
|
|
}
|
|
|
|
if (pwszGuid != NULL)
|
|
{
|
|
if (lstrlen(pwszGuid) >= GUID_STRLEN)
|
|
return ERROR_INVALID_PARAMETER;
|
|
else
|
|
lstrcpy (_pwszGuid, pwszGuid);
|
|
}
|
|
|
|
if (pwszLabel != NULL)
|
|
{
|
|
if (lstrlen(pwszLabel) >= LABEL_STRLEN)
|
|
return ERROR_INVALID_PARAMETER;
|
|
else
|
|
lstrcpy (_pwszLabel, pwszLabel);
|
|
}
|
|
|
|
_dwFlags = dwFlags;
|
|
_prpe = NULL;
|
|
_prp = NULL;
|
|
_iChangeLogs = iChangeLogs;
|
|
_llDataStoreSizeBytes = llSizeLimit;
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: CDataStore::GetVolumeInfo
|
|
//
|
|
// Synopsis: retrieves volume information
|
|
//
|
|
// Arguments:
|
|
//
|
|
// History: 12-Apr-2000 HenryLee Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
DWORD CDataStore::GetVolumeInfo ()
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
WCHAR wcsLabel [LABEL_STRLEN];
|
|
DWORD dwSerial;
|
|
DWORD dwFsFlags;
|
|
|
|
TENTER ("CDataStore::GetVolumeInfo");
|
|
|
|
// Get the volume label and flags
|
|
if (TRUE == GetVolumeInformationW (_pwszGuid,
|
|
wcsLabel, LABEL_STRLEN,
|
|
&dwSerial, NULL, &dwFsFlags, NULL, 0))
|
|
{
|
|
lstrcpy (_pwszLabel, wcsLabel);
|
|
|
|
if (dwFsFlags & FS_VOL_IS_COMPRESSED)
|
|
_dwFlags |= SR_DRIVE_COMPRESSED;
|
|
|
|
if (dwFsFlags & FS_PERSISTENT_ACLS)
|
|
_dwFlags |= SR_DRIVE_NTFS;
|
|
|
|
if (dwFsFlags & FILE_READ_ONLY_VOLUME)
|
|
_dwFlags |= SR_DRIVE_READONLY;
|
|
}
|
|
else
|
|
{
|
|
dwErr = GetLastError();
|
|
TRACE(0, "! CDataStore::GetVolumeInfo : %ld", dwErr);
|
|
}
|
|
|
|
TLEAVE();
|
|
|
|
return dwErr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: CDataStore::Initialize
|
|
//
|
|
// Synopsis: Initialize a datastore object
|
|
//
|
|
// Arguments: [pwszDrive] -- drive letter or mount point
|
|
// [pwszGuid] -- volume GUID
|
|
//
|
|
// Returns: Win32 error code
|
|
//
|
|
// History: 12-Apr-2000 HenryLee Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
DWORD CDataStore::Initialize(WCHAR *pwszDrive, WCHAR *pwszGuid)
|
|
{
|
|
TENTER("CDataStore::Initialize");
|
|
|
|
ULARGE_INTEGER ulTotalFreeBytes;
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
NTSTATUS nts;
|
|
HANDLE h = INVALID_HANDLE_VALUE;
|
|
WCHAR wcsBuffer[MAX_PATH];
|
|
|
|
if (pwszDrive == NULL)
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
if (pwszGuid == NULL)
|
|
{
|
|
if (!GetVolumeNameForVolumeMountPoint (pwszDrive, wcsBuffer, MAX_PATH))
|
|
{
|
|
dwErr = GetLastError();
|
|
TRACE(0, "! CDataStore::Initialize GetVolumeNameForVolumeMountPoint"
|
|
" : %ld", dwErr);
|
|
return dwErr;
|
|
}
|
|
pwszGuid = wcsBuffer;
|
|
}
|
|
|
|
if (lstrlen (pwszDrive) >= MAX_PATH ||
|
|
lstrlen (pwszGuid) >= GUID_STRLEN)
|
|
{
|
|
dwErr = ERROR_INVALID_PARAMETER;
|
|
goto Err;
|
|
}
|
|
|
|
if (DRIVE_FIXED != GetDriveType (pwszDrive))
|
|
return ERROR_BAD_DEV_TYPE;
|
|
|
|
lstrcpy (_pwszDrive, pwszDrive);
|
|
lstrcpy (_pwszGuid, pwszGuid);
|
|
|
|
// Open a handle to the volume
|
|
h = CreateFileW ( pwszGuid,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_FLAG_BACKUP_SEMANTICS,
|
|
NULL );
|
|
|
|
if (h == INVALID_HANDLE_VALUE) // The volume could be unformatted or locked
|
|
{
|
|
dwErr = GetLastError();
|
|
TRACE(0, "! CDataStore::Initialize CreateFileW : %ld", dwErr);
|
|
dwErr = ERROR_UNRECOGNIZED_VOLUME;
|
|
goto Err;
|
|
}
|
|
|
|
dwErr = GetVolumeInfo ();
|
|
if (dwErr != ERROR_SUCCESS)
|
|
goto Err;
|
|
|
|
if (IsSystemDrive (_pwszDrive))
|
|
{
|
|
_dwFlags |= SR_DRIVE_SYSTEM;
|
|
}
|
|
|
|
_dwFlags |= SR_DRIVE_ACTIVE;
|
|
_dwFlags |= SR_DRIVE_MONITORED;
|
|
|
|
Err:
|
|
if (h != INVALID_HANDLE_VALUE)
|
|
CloseHandle (h);
|
|
|
|
TLEAVE();
|
|
|
|
return dwErr;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: CDataStore::UpdateDiskFree
|
|
//
|
|
// Synopsis: calculates disk free and sets initial datastore size
|
|
//
|
|
// Arguments:
|
|
//
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 13-Apr-2000 HenryLee Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
DWORD
|
|
CDataStore::UpdateDiskFree(LONG_PTR lReserved)
|
|
{
|
|
ULARGE_INTEGER ulTotalFreeBytes, ulTotalBytes;
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
const BOOL fSystem = _dwFlags & SR_DRIVE_SYSTEM;
|
|
|
|
if (FALSE == GetDiskFreeSpaceEx (_pwszGuid, NULL, &ulTotalBytes, &ulTotalFreeBytes))
|
|
{
|
|
dwErr = GetLastError();
|
|
goto Err;
|
|
}
|
|
|
|
if (g_pSRConfig != NULL)
|
|
{
|
|
if (_llDataStoreSizeBytes == 0)
|
|
{
|
|
// datastore size calculation
|
|
// minimum = 50mb (non-system) or 200mb (system)
|
|
// maximum = min (disksize, max(12%, 400mb))
|
|
// actual ds size = calculated maximum
|
|
|
|
INT64 llDSQuota = g_pSRConfig->m_dwDiskPercent * ulTotalBytes.QuadPart / 100;
|
|
INT64 llDSMin = (INT64) (g_pSRConfig->GetDSMin(fSystem));
|
|
INT64 llDSMax = min( ulTotalBytes.QuadPart,
|
|
max( llDSQuota, (INT64) g_pSRConfig->m_dwDSMax * MEGABYTE ) );
|
|
|
|
if (llDSMax < llDSMin)
|
|
llDSMax = llDSMin;
|
|
|
|
//
|
|
// take floor of this value
|
|
//
|
|
|
|
_llDataStoreSizeBytes = ((INT64) (llDSMax / (INT64) MEGABYTE)) * (INT64) MEGABYTE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_llDataStoreSizeBytes = SR_DEFAULT_DSMAX * MEGABYTE;
|
|
}
|
|
|
|
_llDiskFreeBytes = (INT64) ulTotalFreeBytes.QuadPart;
|
|
|
|
Err:
|
|
return dwErr;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: CDataStore::UpdateParticipate
|
|
//
|
|
// Synopsis: updates participate bit
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns: boolean
|
|
//
|
|
// History: 27-Apr-2000 brijeshk Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
CDataStore::UpdateParticipate(LONG_PTR pwszDir)
|
|
{
|
|
DWORD dwRc = ERROR_SUCCESS;
|
|
|
|
if (! (_dwFlags & SR_DRIVE_PARTICIPATE))
|
|
{
|
|
WCHAR szPath[MAX_PATH];
|
|
|
|
MakeRestorePath(szPath, _pwszDrive, (LPWSTR) pwszDir);
|
|
if (-1 != GetFileAttributes(szPath))
|
|
{
|
|
dwRc = SetParticipate(TRUE);
|
|
}
|
|
}
|
|
|
|
return dwRc;
|
|
}
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: CDataStore::GetUsagePercent
|
|
//
|
|
// Synopsis: returns datastore usage in percentage
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns: error code
|
|
//
|
|
// History: 27-Apr-2000 brijeshk Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
DWORD CDataStore::GetUsagePercent(int * pnPercent)
|
|
{
|
|
TENTER("CDataStore::GetUsagePercent");
|
|
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
INT64 llAdjustedSize;
|
|
|
|
if (_llDataStoreUsageBytes == -1) // not initialized yet
|
|
{
|
|
dwErr = CalculateDataStoreUsage (NULL);
|
|
if (dwErr != ERROR_SUCCESS)
|
|
goto done;
|
|
}
|
|
|
|
if (_llDiskFreeBytes + _llDataStoreUsageBytes + _llCurrentRpUsageBytes < _llDataStoreSizeBytes)
|
|
{
|
|
llAdjustedSize = _llDiskFreeBytes + _llDataStoreUsageBytes + _llCurrentRpUsageBytes;
|
|
}
|
|
else
|
|
{
|
|
llAdjustedSize = _llDataStoreSizeBytes;
|
|
}
|
|
|
|
|
|
if (llAdjustedSize)
|
|
{
|
|
*pnPercent = (int) ((_llDataStoreUsageBytes + _llCurrentRpUsageBytes) * 100/ llAdjustedSize);
|
|
}
|
|
else
|
|
{
|
|
*pnPercent = 0;
|
|
}
|
|
|
|
TRACE(0, "Datastore %S: Usage=%I64d, Size=%I64d, AdjustedSize=%I64d, Percentage=%d",
|
|
_pwszDrive,
|
|
_llDataStoreUsageBytes + _llCurrentRpUsageBytes,
|
|
_llDataStoreSizeBytes,
|
|
llAdjustedSize,
|
|
*pnPercent);
|
|
|
|
done:
|
|
TLEAVE();
|
|
|
|
return dwErr;
|
|
}
|
|
|
|
DWORD CompressDir_Recurse (WCHAR *pwszPath,
|
|
INT64 *pllDiff,
|
|
INT64 llAllocatedTime,
|
|
ULARGE_INTEGER ulft1,
|
|
ULARGE_INTEGER& ulft2)
|
|
{
|
|
TENTER ("CompressDir_Recurse");
|
|
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
WIN32_FIND_DATAW wfd;
|
|
WCHAR wcsPath [MAX_PATH];
|
|
WCHAR wcsSrch [MAX_PATH];
|
|
|
|
lstrcpy(wcsSrch, pwszPath);
|
|
lstrcat(wcsSrch, L"\\*.*");
|
|
|
|
HANDLE hFind = FindFirstFile (wcsSrch, &wfd);
|
|
|
|
if (hFind != INVALID_HANDLE_VALUE)
|
|
{
|
|
do
|
|
{
|
|
BOOL fDir = wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
|
|
if (!lstrcmp(wfd.cFileName, L".") ||
|
|
!lstrcmp(wfd.cFileName, L"..") ||
|
|
(wfd.dwFileAttributes & FILE_ATTRIBUTE_COMPRESSED) ||
|
|
(wfd.dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
lstrcpyW (wcsPath, pwszPath);
|
|
lstrcatW (wcsPath, L"\\");
|
|
lstrcatW (wcsPath, wfd.cFileName);
|
|
|
|
if (fDir)
|
|
{
|
|
dwErr = CompressDir_Recurse (wcsPath, pllDiff, llAllocatedTime, ulft1, ulft2);
|
|
if (dwErr != ERROR_SUCCESS)
|
|
break;
|
|
}
|
|
|
|
dwErr = CompressFile (wcsPath, TRUE, fDir);
|
|
if (ERROR_SUCCESS != dwErr)
|
|
break;
|
|
|
|
if (!fDir)
|
|
{
|
|
LARGE_INTEGER ulBefore;
|
|
ULARGE_INTEGER ulAfter;
|
|
|
|
ulBefore.HighPart = wfd.nFileSizeHigh;
|
|
ulBefore.LowPart = wfd.nFileSizeLow;
|
|
|
|
ulAfter.LowPart = GetCompressedFileSize (wcsPath,
|
|
&ulAfter.HighPart);
|
|
if (ulAfter.LowPart == 0xFFFFFFFF)
|
|
{
|
|
dwErr = GetLastError();
|
|
TRACE(0, "! GetCompressedFileSize : %ld", dwErr);
|
|
break;
|
|
}
|
|
|
|
*pllDiff += ulAfter.QuadPart - ulBefore.QuadPart;
|
|
}
|
|
|
|
FILETIME ft2;
|
|
|
|
GetSystemTimeAsFileTime (&ft2);
|
|
ulft2.LowPart = ft2.dwLowDateTime;
|
|
ulft2.HighPart = ft2.dwHighDateTime;
|
|
|
|
// check to see if we need to exit
|
|
if (llAllocatedTime < ulft2.QuadPart - ulft1.QuadPart)
|
|
{
|
|
TRACE(0, "Timed out - aborting compression");
|
|
dwErr = ERROR_OPERATION_ABORTED;
|
|
break;
|
|
}
|
|
|
|
ASSERT(g_pSRConfig);
|
|
if (IsStopSignalled(g_pSRConfig->m_hSRStopEvent))
|
|
{
|
|
TRACE(0, "Stop signalled - aborting compression");
|
|
dwErr = ERROR_OPERATION_ABORTED;
|
|
break;
|
|
}
|
|
}
|
|
while (FindNextFile (hFind, &wfd));
|
|
FindClose (hFind);
|
|
}
|
|
|
|
TLEAVE();
|
|
|
|
return dwErr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: CDataStore::Compress
|
|
//
|
|
// Synopsis: compress a file in this datastore
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns: Win32 error code
|
|
//
|
|
// History: 12-Apr-2000 HenryLee Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
DWORD CDataStore::Compress (INT64 llAllocatedTime, INT64 *pllUsed)
|
|
{
|
|
TENTER ("CDataStore::Compress");
|
|
|
|
if (g_pSRConfig != NULL &&
|
|
TRUE == g_pSRConfig->GetSafeMode()) // do not compress in SafeMode
|
|
{
|
|
return ERROR_BAD_ENVIRONMENT;
|
|
}
|
|
|
|
if (_dwFlags & SR_DRIVE_READONLY) // cannot compress read-only volumes
|
|
return ERROR_SUCCESS;
|
|
|
|
ULARGE_INTEGER ulft1, ulft2;
|
|
FILETIME ft1, ft2;
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
WCHAR wcsPath[MAX_PATH];
|
|
|
|
GetSystemTimeAsFileTime (&ft1);
|
|
ulft1.LowPart = ft1.dwLowDateTime;
|
|
ulft1.HighPart = ft1.dwHighDateTime;
|
|
|
|
ulft2.LowPart = ft1.dwLowDateTime;
|
|
ulft2.HighPart = ft1.dwHighDateTime;
|
|
|
|
if (_prp == NULL)
|
|
{
|
|
_prp = new CRestorePoint;
|
|
if (_prp == NULL)
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
_prpe = new CRestorePointEnum (_pwszDrive, TRUE, TRUE);
|
|
if (_prpe == NULL)
|
|
{
|
|
delete _prp;
|
|
_prp = NULL;
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
dwErr = _prpe->FindFirstRestorePoint( * _prp );
|
|
if (dwErr != ERROR_SUCCESS)
|
|
{
|
|
dwErr = ERROR_SUCCESS; // no restore points to compress
|
|
goto Err;
|
|
}
|
|
}
|
|
|
|
if (g_pSRConfig->m_dwTestBroadcast)
|
|
PostTestMessage(g_pSRConfig->m_uiTMCompressStart, (WPARAM) _pwszDrive[0], NULL);
|
|
|
|
do
|
|
{
|
|
MakeRestorePath(wcsPath, _pwszDrive, _prp->GetDir());
|
|
|
|
//
|
|
// patch the snapshot directory on system drive
|
|
//
|
|
|
|
// BUGBUG - add a time restriction to this
|
|
// and factor this into the compression time allocated
|
|
|
|
if (_dwFlags & SR_DRIVE_SYSTEM)
|
|
{
|
|
WCHAR wcsSnapshot[MAX_PATH];
|
|
|
|
lstrcpy(wcsSnapshot, wcsPath);
|
|
lstrcat(wcsSnapshot, L"\\snapshot");
|
|
|
|
dwErr = PatchComputePatch(wcsSnapshot);
|
|
if (dwErr != ERROR_SUCCESS)
|
|
{
|
|
trace(0, "! PatchComputePatch : %ld", dwErr);
|
|
goto Err;
|
|
}
|
|
}
|
|
|
|
|
|
if (_dwFlags & SR_DRIVE_NTFS) // use NTFS compression
|
|
{
|
|
|
|
|
|
INT64 llDiff = 0;
|
|
|
|
dwErr = CompressDir_Recurse (wcsPath, &llDiff, llAllocatedTime, ulft1, ulft2);
|
|
|
|
if (llDiff != 0)
|
|
{
|
|
INT64 llSize = 0;
|
|
if (ERROR_SUCCESS == _prp->ReadSize (_pwszDrive, &llSize ))
|
|
_prp->WriteSize (_pwszDrive, llSize + llDiff);
|
|
|
|
if (_llDataStoreUsageBytes != -1) // counter initialized
|
|
_llDataStoreUsageBytes += llDiff;
|
|
}
|
|
|
|
// check to see if we need to exit
|
|
if (ERROR_SUCCESS != dwErr && ERROR_OPERATION_ABORTED != dwErr)
|
|
break;
|
|
}
|
|
}
|
|
while (dwErr != ERROR_OPERATION_ABORTED && ERROR_SUCCESS == _prpe->FindNextRestorePoint ( * _prp ));
|
|
|
|
*pllUsed = ulft2.QuadPart - ulft1.QuadPart;
|
|
trace(0, "Compression on drive %S used up %I64d", _pwszDrive, *pllUsed);
|
|
|
|
if (g_pSRConfig->m_dwTestBroadcast)
|
|
PostTestMessage(g_pSRConfig->m_uiTMCompressStop, (WPARAM) _pwszDrive[0], NULL);
|
|
|
|
Err:
|
|
if (ERROR_SUCCESS == dwErr) // if we finished everything
|
|
{
|
|
delete _prpe;
|
|
_prpe = NULL;
|
|
|
|
delete _prp;
|
|
_prp = NULL;
|
|
}
|
|
|
|
TLEAVE();
|
|
|
|
return dwErr;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: CDataStore::UpdateDataStoreUsage
|
|
//
|
|
// Synopsis: incremental update of usage byte count
|
|
//
|
|
// Arguments: [llDelta] -- add this amount to the total
|
|
// [fCurrent] -- update current restore point's size
|
|
//
|
|
// Returns: Win32 error code
|
|
//
|
|
// History: 12-Apr-2000 HenryLee Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
DWORD CDataStore::UpdateDataStoreUsage(INT64 llDelta, BOOL fCurrent)
|
|
{
|
|
TENTER ("CDataStore::UpdateDataStoreUsage");
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
|
|
if (_llDataStoreUsageBytes != -1) // counter is initialized
|
|
{
|
|
if (fCurrent)
|
|
{
|
|
CRestorePoint rpCur;
|
|
|
|
_llCurrentRpUsageBytes += llDelta;
|
|
if (_llCurrentRpUsageBytes < 0)
|
|
_llCurrentRpUsageBytes = 0;
|
|
|
|
CHECKERR(GetCurrentRestorePoint(rpCur),
|
|
"GetCurrentRestorePoint");
|
|
|
|
CHECKERR(rpCur.WriteSize(_pwszDrive, _llCurrentRpUsageBytes),
|
|
"WriteSize");
|
|
}
|
|
else
|
|
{
|
|
_llDataStoreUsageBytes += llDelta;
|
|
if (_llDataStoreUsageBytes < 0)
|
|
_llDataStoreUsageBytes = 0;
|
|
}
|
|
}
|
|
|
|
Err:
|
|
TLEAVE();
|
|
return dwErr;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: CDataStore::CalculateRpUsage
|
|
//
|
|
// Synopsis: get disk space used by restore point on this volume
|
|
//
|
|
// Arguments: prp - pointer to restore point object
|
|
// pllTemp - pointer to variable that stores calculated size
|
|
// fForce - ignore existing restorepointsize file
|
|
// fSnapshotOnly - calculate size of snapshot only
|
|
//
|
|
// Returns: Win32 error code
|
|
//
|
|
// History: 12-Apr-2000 HenryLee Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
DWORD CDataStore::CalculateRpUsage(
|
|
CRestorePoint *prp,
|
|
INT64* pllTemp,
|
|
BOOL fForce,
|
|
BOOL fSnapshotOnly)
|
|
{
|
|
TENTER("CDataStore::CalculateRpUsage");
|
|
|
|
WCHAR wcsPath[MAX_PATH];
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
|
|
if (! fForce)
|
|
{
|
|
dwErr = prp->ReadSize(_pwszDrive, pllTemp);
|
|
}
|
|
|
|
if (fForce || dwErr != ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// recalculate size
|
|
// when a new restore point is created, only calculate
|
|
// the snapshot size
|
|
// filter will notify us at 25mb intervals
|
|
// and we will accurately calculate the size when the restore
|
|
// point is closed
|
|
//
|
|
|
|
MakeRestorePath(wcsPath, _pwszDrive, prp->GetDir());
|
|
if (fSnapshotOnly)
|
|
{
|
|
lstrcat(wcsPath, L"\\snapshot");
|
|
}
|
|
|
|
*pllTemp = 0;
|
|
dwErr = GetFileSize_Recurse (wcsPath, pllTemp,
|
|
g_pDataStoreMgr->GetStopFlag());
|
|
|
|
if (dwErr == ERROR_PATH_NOT_FOUND)
|
|
{
|
|
dwErr = ERROR_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
dwErr = prp->WriteSize(_pwszDrive, *pllTemp);
|
|
}
|
|
|
|
}
|
|
|
|
return dwErr;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: CDataStore::CalculateDataStoreUsage
|
|
//
|
|
// Synopsis: get disk space used by data store and volume
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns: Win32 error code
|
|
//
|
|
// History: 12-Apr-2000 HenryLee Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
DWORD CDataStore::CalculateDataStoreUsage(LONG_PTR lReserved)
|
|
{
|
|
TENTER ("CDataStore::CalculateDataStoreUsage");
|
|
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
|
|
CRestorePointEnum rpe (_pwszDrive, TRUE, TRUE); // enum forward, skipping current
|
|
CRestorePoint rp;
|
|
|
|
_llDataStoreUsageBytes = 0;
|
|
|
|
dwErr = rpe.FindFirstRestorePoint(rp);
|
|
|
|
while (ERROR_SUCCESS == dwErr || dwErr == ERROR_FILE_NOT_FOUND)
|
|
{
|
|
INT64 llTemp = 0;
|
|
|
|
CHECKERR(
|
|
CalculateRpUsage(
|
|
&rp,
|
|
&llTemp,
|
|
FALSE, // don't force
|
|
FALSE), // everything
|
|
"CalculateRpUsage");
|
|
|
|
_llDataStoreUsageBytes += llTemp;
|
|
|
|
dwErr = rpe.FindNextRestorePoint (rp);
|
|
}
|
|
|
|
rpe.FindClose ();
|
|
|
|
if (dwErr == ERROR_NO_MORE_ITEMS)
|
|
dwErr = ERROR_SUCCESS;
|
|
|
|
//
|
|
// get the size of the current restore point
|
|
//
|
|
|
|
CHECKERR(GetCurrentRestorePoint(rp),
|
|
"GetCurrentRestorePoint");
|
|
|
|
CHECKERR(CalculateRpUsage(&rp,
|
|
&_llCurrentRpUsageBytes,
|
|
FALSE,
|
|
FALSE),
|
|
"CalculateRpUsage");
|
|
|
|
Err:
|
|
TLEAVE();
|
|
|
|
return dwErr;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: CDataStore::CreateDataStore
|
|
//
|
|
// Synopsis: create the _restore directory and pertinent files
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns: Win32 error code
|
|
//
|
|
// History: 12-Apr-2000 HenryLee Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
DWORD CDataStore::CreateDataStore (LONG_PTR lReserved)
|
|
{
|
|
TENTER("CDataStore::CreateDataStore");
|
|
|
|
ULARGE_INTEGER ulTotalFreeBytes;
|
|
SECURITY_ATTRIBUTES *psa = NULL;
|
|
SECURITY_ATTRIBUTES *psa2 = NULL;
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
DWORD dwAttrs = 0;
|
|
WCHAR wcsPath[MAX_PATH];
|
|
|
|
SECURITY_ATTRIBUTES sa;
|
|
SECURITY_ATTRIBUTES sa2;
|
|
SECURITY_DESCRIPTOR sd;
|
|
SECURITY_DESCRIPTOR sd2;
|
|
SID *pSid = NULL;
|
|
|
|
if (_dwFlags & SR_DRIVE_NTFS)
|
|
{
|
|
struct
|
|
{
|
|
ACL acl; // the ACL header
|
|
BYTE rgb[ 128 - sizeof(ACL) ]; // buffer to hold 2 ACEs
|
|
} DaclBuffer;
|
|
|
|
struct
|
|
{
|
|
ACL acl; // the ACL header
|
|
BYTE rgb[ 128 - sizeof(ACL) ]; // buffer to hold 2 ACEs
|
|
} DaclBuffer2;
|
|
|
|
SID_IDENTIFIER_AUTHORITY SaNT = SECURITY_NT_AUTHORITY;
|
|
SID_IDENTIFIER_AUTHORITY SaWorld = SECURITY_WORLD_SID_AUTHORITY;
|
|
|
|
if (!InitializeAcl(&DaclBuffer.acl, sizeof(DaclBuffer), ACL_REVISION))
|
|
{
|
|
dwErr = GetLastError();
|
|
goto Err;
|
|
}
|
|
|
|
// Create the SID. We'll give the local system full access
|
|
|
|
if( !AllocateAndInitializeSid( &SaNT, // Top-level authority
|
|
1, SECURITY_LOCAL_SYSTEM_RID,
|
|
0, 0, 0, 0, 0, 0, 0,
|
|
(void **) &pSid ))
|
|
{
|
|
dwErr = GetLastError();
|
|
TRACE(0, "! AllocateAndInitializeSid : %ld", dwErr);
|
|
goto Err;
|
|
}
|
|
|
|
|
|
if (!AddAccessAllowedAce( &DaclBuffer.acl,
|
|
ACL_REVISION,
|
|
STANDARD_RIGHTS_ALL | GENERIC_ALL,
|
|
pSid ))
|
|
{
|
|
dwErr = GetLastError();
|
|
TRACE(0, "! AddAccessAllowedAce : %ld", dwErr);
|
|
goto Err;
|
|
}
|
|
|
|
if (!InitializeAcl(&DaclBuffer2.acl, sizeof(DaclBuffer2), ACL_REVISION))
|
|
{
|
|
dwErr = GetLastError();
|
|
goto Err;
|
|
}
|
|
|
|
FreeSid (pSid);
|
|
if( !AllocateAndInitializeSid( &SaWorld, // Top-level authority
|
|
1, SECURITY_WORLD_RID,
|
|
0, 0, 0, 0, 0, 0, 0,
|
|
(void **) &pSid ))
|
|
{
|
|
dwErr = GetLastError();
|
|
TRACE(0, "! AllocateAndInitializeSid : %ld", dwErr);
|
|
goto Err;
|
|
}
|
|
|
|
|
|
if (!AddAccessAllowedAceEx ( &DaclBuffer2.acl,
|
|
ACL_REVISION,
|
|
CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE,
|
|
STANDARD_RIGHTS_ALL | GENERIC_ALL,
|
|
pSid ))
|
|
{
|
|
dwErr = GetLastError();
|
|
TRACE(0, "! AddAccessAllowedAce : %ld", dwErr);
|
|
goto Err;
|
|
}
|
|
|
|
// Set up the security descriptor with that DACL in it.
|
|
|
|
if (!InitializeSecurityDescriptor( &sd, SECURITY_DESCRIPTOR_REVISION ))
|
|
{
|
|
dwErr = GetLastError();
|
|
TRACE(0, "! InitializeSecurityDescriptor : %ld", dwErr);
|
|
goto Err;
|
|
}
|
|
|
|
if( !SetSecurityDescriptorDacl( &sd, TRUE, &DaclBuffer.acl, FALSE ))
|
|
{
|
|
dwErr = GetLastError();
|
|
TRACE(0, "! SetSecurityDescriptorDacl : %ld", dwErr);
|
|
goto Err;
|
|
}
|
|
|
|
if (!InitializeSecurityDescriptor( &sd2, SECURITY_DESCRIPTOR_REVISION ))
|
|
{
|
|
dwErr = GetLastError();
|
|
TRACE(0, "! InitializeSecurityDescriptor : %ld", dwErr);
|
|
goto Err;
|
|
}
|
|
|
|
if( !SetSecurityDescriptorDacl( &sd2, TRUE, &DaclBuffer2.acl, FALSE ))
|
|
{
|
|
dwErr = GetLastError();
|
|
TRACE(0, "! SetSecurityDescriptorDacl : %ld", dwErr);
|
|
goto Err;
|
|
}
|
|
|
|
if( !SetSecurityDescriptorControl( &sd2,
|
|
SE_DACL_PROTECTED,
|
|
SE_DACL_PROTECTED ))
|
|
{
|
|
dwErr = GetLastError();
|
|
TRACE(0, "! SetSecurityDescriptorControl : %ld", dwErr);
|
|
goto Err;
|
|
}
|
|
|
|
// Put the security descriptor into the security attributes.
|
|
|
|
ZeroMemory (&sa, sizeof(sa));
|
|
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
|
|
sa.lpSecurityDescriptor = &sd;
|
|
sa.bInheritHandle = TRUE;
|
|
|
|
psa = &sa;
|
|
|
|
ZeroMemory (&sa2, sizeof(sa2));
|
|
sa2.nLength = sizeof(SECURITY_ATTRIBUTES);
|
|
sa2.lpSecurityDescriptor = &sd2;
|
|
sa2.bInheritHandle = TRUE;
|
|
|
|
psa2 = &sa2;
|
|
}
|
|
|
|
|
|
// create "System Volume Information" if it does not exist
|
|
// set "system only" dacl on this directory
|
|
// make this S+H+non-CI
|
|
|
|
wsprintf(wcsPath, L"%s%s", _pwszDrive, s_cszSysVolInfo);
|
|
if (-1 == GetFileAttributes(wcsPath))
|
|
{
|
|
if (FALSE == CreateDirectoryW(wcsPath, psa))
|
|
{
|
|
dwErr = GetLastError();
|
|
TRACE(0, "! CreateDirectoryW for %s : %ld", wcsPath, dwErr);
|
|
goto Err;
|
|
}
|
|
|
|
if (FALSE == SetFileAttributesW (wcsPath,
|
|
FILE_ATTRIBUTE_NOT_CONTENT_INDEXED |
|
|
FILE_ATTRIBUTE_HIDDEN |
|
|
FILE_ATTRIBUTE_SYSTEM))
|
|
{
|
|
dwErr = GetLastError();
|
|
TRACE(0, "! SetFileAttributes for %s : %ld", wcsPath, dwErr);
|
|
goto Err;
|
|
}
|
|
}
|
|
|
|
// now create our _Restore directory
|
|
// don't put any dacl on it
|
|
|
|
MakeRestorePath (wcsPath, _pwszDrive, L"");
|
|
|
|
dwAttrs = GetFileAttributes(wcsPath);
|
|
if (-1 != dwAttrs && !(FILE_ATTRIBUTE_DIRECTORY & dwAttrs))
|
|
{
|
|
DeleteFileW (wcsPath); // try deleting the file
|
|
}
|
|
|
|
if (FALSE == CreateDirectoryW (wcsPath, psa2))
|
|
{
|
|
dwErr = GetLastError();
|
|
|
|
if (ERROR_ALREADY_EXISTS == dwErr)
|
|
{
|
|
if (psa2 != NULL && FALSE == SetFileSecurity (wcsPath,
|
|
DACL_SECURITY_INFORMATION,
|
|
&sd2))
|
|
{
|
|
dwErr = GetLastError();
|
|
TRACE(0, "! SetFileSecurity for %s : %ld", wcsPath, dwErr);
|
|
}
|
|
else
|
|
dwErr = ERROR_SUCCESS;
|
|
}
|
|
|
|
if (dwErr != ERROR_SUCCESS)
|
|
{
|
|
TRACE(0, "! CreateDataStore CreateDirectoryW : %ld", dwErr);
|
|
goto Err;
|
|
}
|
|
}
|
|
|
|
//
|
|
// let's keep the datastore uncompressed
|
|
// so that filter can make quicker unbuffered copies
|
|
//
|
|
|
|
#if 0
|
|
// If the datastore is marked uncompressed, mark it compressed
|
|
//
|
|
if (_dwFlags & SR_DRIVE_NTFS)
|
|
{
|
|
dwAttrs = GetFileAttributesW (wcsPath);
|
|
if (dwAttrs != INVALID_FILE_SIZE &&
|
|
0 == (FILE_ATTRIBUTE_COMPRESSED & dwAttrs))
|
|
{
|
|
dwErr = CompressFile ( wcsPath, TRUE, TRUE );
|
|
|
|
if (dwErr != ERROR_SUCCESS)
|
|
{
|
|
TRACE(0, "! CreateDataStore CompressFile : %ld", dwErr);
|
|
goto Err;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (FALSE == SetFileAttributesW (wcsPath,
|
|
FILE_ATTRIBUTE_NOT_CONTENT_INDEXED |
|
|
FILE_ATTRIBUTE_HIDDEN |
|
|
FILE_ATTRIBUTE_SYSTEM))
|
|
{
|
|
dwErr = GetLastError();
|
|
TRACE(0, "! CreateDataStore SetFileAttributesW : %ld", dwErr);
|
|
}
|
|
|
|
Err:
|
|
if (pSid != NULL)
|
|
FreeSid (pSid);
|
|
|
|
TLEAVE();
|
|
|
|
return dwErr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: CDataStore::DestroyDataStore
|
|
//
|
|
// Synopsis: remove the _restore directory and pertinent files
|
|
//
|
|
// Arguments: [fDeleteDir] -- TRUE if deleting parent directory
|
|
//
|
|
// Returns: Win32 error code
|
|
//
|
|
// History: 12-Apr-2000 HenryLee Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
DWORD CDataStore::DestroyDataStore (LONG_PTR fDeleteDir)
|
|
{
|
|
TENTER("CDataStore::DestroyDataStore");
|
|
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
WCHAR wcsPath[MAX_PATH];
|
|
|
|
MakeRestorePath (wcsPath, _pwszDrive, L"");
|
|
|
|
// delete the restore directory
|
|
dwErr = Delnode_Recurse (wcsPath, (BOOL) fDeleteDir,
|
|
g_pDataStoreMgr->GetStopFlag());
|
|
|
|
if (_dwFlags & SR_DRIVE_SYSTEM)
|
|
{
|
|
g_pDataStoreMgr->DeleteMachineGuidFile();
|
|
}
|
|
|
|
if (ERROR_SUCCESS == dwErr)
|
|
{
|
|
_llDataStoreUsageBytes = 0;
|
|
_llCurrentRpUsageBytes = 0;
|
|
}
|
|
|
|
TLEAVE();
|
|
|
|
return dwErr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: CDataStore::MonitorDrive
|
|
//
|
|
// Synopsis: tell the filter to start/stop monitoring this drive
|
|
//
|
|
// Arguments: [fStart] -- TRUE start monitoring, FALSE stop monitoring
|
|
//
|
|
// Returns: Win32 error code
|
|
//
|
|
// History: 12-Apr-2000 HenryLee Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
DWORD CDataStore::MonitorDrive (LONG_PTR fSet)
|
|
{
|
|
DWORD dwRc = ERROR_SUCCESS;
|
|
HANDLE hEventSource = NULL;
|
|
|
|
TENTER("CDataStore::MonitorDrive");
|
|
|
|
if (!fSet)
|
|
{
|
|
// if the drive is already disabled, then no op
|
|
|
|
if (! (_dwFlags & SR_DRIVE_MONITORED))
|
|
goto done;
|
|
|
|
dwRc = SrDisableVolume(g_pSRConfig->GetFilter(), GetNTName());
|
|
if (dwRc != ERROR_SUCCESS)
|
|
goto done;
|
|
|
|
_dwFlags &= ~SR_DRIVE_MONITORED;
|
|
|
|
// reset any per-rp flags as well
|
|
ResetFlags(NULL);
|
|
|
|
dwRc = DestroyDataStore(TRUE);
|
|
}
|
|
else
|
|
{
|
|
// if the drive is already enabled, then no op
|
|
|
|
if (_dwFlags & SR_DRIVE_MONITORED)
|
|
{
|
|
dwRc = ERROR_SERVICE_ALREADY_RUNNING;
|
|
goto done;
|
|
}
|
|
|
|
_dwFlags |= SR_DRIVE_MONITORED;
|
|
|
|
// reset any per-rp flags as well
|
|
ResetFlags(NULL);
|
|
}
|
|
|
|
DirtyDriveTable();
|
|
|
|
trace(0, "****%S drive %S****", fSet ? L"Enabled" : L"Disabled", _pwszDrive);
|
|
|
|
hEventSource = RegisterEventSource(NULL, s_cszServiceName);
|
|
if (hEventSource != NULL)
|
|
{
|
|
SRLogEvent (hEventSource, EVENTLOG_INFORMATION_TYPE, fSet ? EVMSG_DRIVE_ENABLED : EVMSG_DRIVE_DISABLED,
|
|
NULL, 0, _pwszDrive, NULL, NULL);
|
|
DeregisterEventSource(hEventSource);
|
|
}
|
|
|
|
|
|
if (g_pSRConfig->m_dwTestBroadcast)
|
|
PostTestMessage( fSet ? g_pSRConfig->m_uiTMEnable : g_pSRConfig->m_uiTMDisable,
|
|
(WPARAM) _pwszDrive[0],
|
|
NULL);
|
|
|
|
done:
|
|
TLEAVE();
|
|
return dwRc;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: CDataStore::FreezeDrive
|
|
//
|
|
// Synopsis: tell the filter to freeze this drive
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns: Win32 error code
|
|
//
|
|
// History: 04-Jun-2000 brijeshk Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
DWORD CDataStore::FreezeDrive (LONG_PTR lReserved)
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
|
|
TENTER("CDataStore::FreezeDrive");
|
|
|
|
_dwFlags |= SR_DRIVE_FROZEN; // freeze in spite of open file handles
|
|
|
|
// if the drive is disabled, no op
|
|
|
|
if (! (_dwFlags & SR_DRIVE_MONITORED))
|
|
goto Err;
|
|
|
|
//
|
|
// check if the drive exists before calling the driver
|
|
//
|
|
|
|
if (0xFFFFFFFF == GetFileAttributes(_pwszGuid))
|
|
{
|
|
trace(0, "Drive %s does not exist", _pwszDrive);
|
|
goto Err;
|
|
}
|
|
|
|
CHECKERR(SrDisableVolume(g_pSRConfig->GetFilter(), GetNTName()),
|
|
"SrDisableVolume");
|
|
|
|
DestroyDataStore(FALSE);
|
|
|
|
DirtyDriveTable();
|
|
|
|
trace(0, "****Froze drive %S****", _pwszDrive);
|
|
|
|
Err:
|
|
TLEAVE();
|
|
return dwErr;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: CDataStore::ThawDrive
|
|
//
|
|
// Synopsis: check and thaw this drive
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns: Win32 error code
|
|
//
|
|
// History: 04-Jun-2000 brijeshk Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
DWORD CDataStore::ThawDrive(LONG_PTR fCheckOnly)
|
|
{
|
|
DWORD dwRc = ERROR_SUCCESS;
|
|
|
|
TENTER("CDataStore::ThawDrive");
|
|
|
|
if (_dwFlags & SR_DRIVE_FROZEN)
|
|
{
|
|
//Actually we want to clean up everything except for the
|
|
//current restore point
|
|
//dwRc = DestroyDataStore(FALSE);
|
|
if (ERROR_SUCCESS == dwRc)
|
|
{
|
|
_dwFlags &= ~SR_DRIVE_FROZEN;
|
|
DirtyDriveTable();
|
|
trace(0, "****Thawed drive %S****", _pwszDrive);
|
|
}
|
|
else trace(0, "Cannot thaw %S error %d", _pwszDrive, dwRc);
|
|
}
|
|
|
|
TLEAVE();
|
|
return dwRc;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Functiion CDataStore::FifoRestorePoint
|
|
//
|
|
// Synopsis: fifo one restore point in this datastore
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns: Win32 error code
|
|
//
|
|
// History: 12-Apr-2000 BrijeshK Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
CDataStore::FifoRestorePoint(
|
|
CRestorePoint& rp)
|
|
{
|
|
TENTER("CDataStore::FifoRestorePoint");
|
|
|
|
WCHAR szRpPath[MAX_PATH], szFifoedPath[MAX_PATH];
|
|
INT64 llSize = 0;
|
|
DWORD dwRc;
|
|
|
|
//
|
|
// if patching is on, and this is a reference directory
|
|
// for later snapshots, then don't fifo the snapshot folder
|
|
// rename it to RefRPx, and keep it around
|
|
// BUGBUG - how do we update size correctly ?
|
|
//
|
|
|
|
if (PatchGetPatchWindow() != 0)
|
|
{
|
|
// if Reference(RPx) == x, then x is a reference rp
|
|
|
|
if (PatchGetReferenceRpNum(rp.GetNum()) == rp.GetNum())
|
|
{
|
|
WCHAR szRp[MAX_RP_PATH + sizeof(s_cszReferenceDir)/sizeof(WCHAR)];
|
|
|
|
MakeRestorePath(szRpPath, _pwszDrive, rp.GetDir());
|
|
lstrcat(szRpPath, SNAPSHOT_DIR_NAME);
|
|
|
|
wsprintf(szRp, L"%s%ld", s_cszReferenceDir, rp.GetNum());
|
|
MakeRestorePath(szFifoedPath, _pwszDrive, szRp);
|
|
CreateDirectory(szFifoedPath, NULL);
|
|
|
|
lstrcat(szFifoedPath, SNAPSHOT_DIR_NAME);
|
|
MoveFile(szRpPath, szFifoedPath);
|
|
}
|
|
}
|
|
|
|
// read the size of this restore point
|
|
// but don't update the datastore size yet
|
|
|
|
dwRc = rp.ReadSize(_pwszDrive, &llSize);
|
|
|
|
|
|
// move the rp dir to a temp dir "Fifoed"
|
|
// this is to make the fifo of a single rp atomic
|
|
// to take care of unclean shutdowns
|
|
|
|
MakeRestorePath(szRpPath, _pwszDrive, rp.GetDir());
|
|
MakeRestorePath(szFifoedPath, _pwszDrive, s_cszFifoedRpDir);
|
|
|
|
if (! MoveFile(szRpPath, szFifoedPath))
|
|
{
|
|
dwRc = GetLastError();
|
|
TRACE(0, "! MoveFile from %S to %S : %ld", szRpPath, szFifoedPath, dwRc);
|
|
goto done;
|
|
}
|
|
|
|
|
|
// now examine the result of rp.ReadSize
|
|
// and update the datastore usage variable
|
|
|
|
if (ERROR_SUCCESS == dwRc)
|
|
{
|
|
UpdateDataStoreUsage (-llSize, FALSE);
|
|
}
|
|
else
|
|
{
|
|
// ignore this error and continue
|
|
|
|
TRACE(0, "! rp.ReadSize : %ld", dwRc);
|
|
}
|
|
|
|
|
|
// blow away the temp fifoed directory again
|
|
|
|
dwRc = Delnode_Recurse(szFifoedPath, TRUE,
|
|
g_pDataStoreMgr->GetStopFlag());
|
|
if (ERROR_SUCCESS != dwRc)
|
|
{
|
|
TRACE(0, "! Delnode_Recurse : %ld", dwRc);
|
|
goto done;
|
|
}
|
|
|
|
done:
|
|
TLEAVE();
|
|
return dwRc;
|
|
}
|
|
|
|
|
|
DWORD
|
|
CDataStore::Print(LONG_PTR lptr)
|
|
{
|
|
TENTER("CDataStore::Print");
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
DWORD cbWritten;
|
|
HANDLE h = (HANDLE) lptr;
|
|
|
|
WCHAR w[1024];
|
|
|
|
wsprintf(w, L"Drive: %s, Guid: %s\r\n", _pwszDrive, _pwszGuid);
|
|
WriteFile (h, (BYTE *) w, lstrlen(w) * sizeof(WCHAR), &cbWritten, NULL);
|
|
|
|
trace(0, "Drive: %S, Guid: %S", _pwszDrive, _pwszGuid);
|
|
|
|
wsprintf(w, L"\t%s %s %s %s %s %s %s %s\r\n",
|
|
_dwFlags & SR_DRIVE_ACTIVE ? L"Active, " : L"",
|
|
_dwFlags & SR_DRIVE_COMPRESSED ? L"Compressed, " : L"",
|
|
_dwFlags & SR_DRIVE_MONITORED ? L"Monitored, " : L"",
|
|
_dwFlags & SR_DRIVE_NTFS ? L"NTFS, " : L"",
|
|
_dwFlags & SR_DRIVE_PARTICIPATE ? L"Participate, " : L"",
|
|
_dwFlags & SR_DRIVE_FROZEN ? L"Frozen, " : L"",
|
|
_dwFlags & SR_DRIVE_READONLY ? L"ReadOnly, " : L"",
|
|
_dwFlags & SR_DRIVE_ERROR ? L"Error" : L"");
|
|
WriteFile (h, (BYTE *) w, lstrlen(w) * sizeof(WCHAR), &cbWritten, NULL);
|
|
|
|
trace(0, "%S %S %S %S", _dwFlags & SR_DRIVE_ACTIVE ? L"Active, " : L"",
|
|
_dwFlags & SR_DRIVE_COMPRESSED ? L"Compressed, " : L"",
|
|
_dwFlags & SR_DRIVE_MONITORED ? L"Monitored, " : L"",
|
|
_dwFlags & SR_DRIVE_NTFS ? L"NTFS, " : L"");
|
|
|
|
trace(0, "%S %S %S %S", _dwFlags & SR_DRIVE_PARTICIPATE ? L"Participate, " : L"",
|
|
_dwFlags & SR_DRIVE_FROZEN ? L"Frozen, " : L"",
|
|
_dwFlags & SR_DRIVE_READONLY ? L"ReadOnly, " : L"",
|
|
_dwFlags & SR_DRIVE_ERROR ? L"Error" : L"");
|
|
|
|
wsprintf(w, L"\tSize: %I64d, Usage: %I64d, Diskfree: %I64d\r\n\r\n",
|
|
_llDataStoreSizeBytes,
|
|
_llDataStoreUsageBytes + _llCurrentRpUsageBytes,
|
|
_llDiskFreeBytes);
|
|
WriteFile (h, (BYTE *) w, lstrlen(w) * sizeof(WCHAR), &cbWritten, NULL);
|
|
|
|
trace(0, "Size: %I64d, Usage: %I64d, Diskfree: %I64d",
|
|
_llDataStoreSizeBytes,
|
|
_llDataStoreUsageBytes + _llCurrentRpUsageBytes,
|
|
_llDiskFreeBytes);
|
|
|
|
TLEAVE();
|
|
return dwErr;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Functiion CDataStore::SaveDataStore
|
|
//
|
|
// Synopsis: save datastore info as a line in the drive table
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns: Win32 error code
|
|
//
|
|
// History: 12-Apr-2000 HenryLee Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
DWORD CDataStore::SaveDataStore (LONG_PTR hFile)
|
|
{
|
|
HANDLE h = (HANDLE) hFile;
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
WCHAR wcsBuffer[MAX_PATH * 2];
|
|
DWORD cbWritten = 0;
|
|
|
|
wsprintf (wcsBuffer, gs_wcsPrintFormat,
|
|
GetDrive(), GetGuid(), _dwFlags,
|
|
GetNumChangeLogs(), (DWORD) (GetSizeLimit() / (INT64) MEGABYTE),
|
|
GetLabel());
|
|
|
|
if (FALSE == WriteFile (h, (BYTE *) wcsBuffer,
|
|
lstrlen(wcsBuffer) * sizeof(WCHAR), &cbWritten, NULL))
|
|
{
|
|
dwErr = GetLastError();
|
|
}
|
|
return dwErr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Functiion CDataStore::DirtyDriveTable
|
|
//
|
|
// Synopsis: set the dirty bit in the drive table
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns: Win32 error code
|
|
//
|
|
// History: 12-Apr-2000 HenryLee Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
DWORD CDataStore::DirtyDriveTable ()
|
|
{
|
|
if (_pdt != NULL)
|
|
_pdt->SetDirty ();
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Functiion CDataStore::SwitchRestorePoint
|
|
//
|
|
// Synopsis: change the drive table when switching restore points
|
|
//
|
|
// Arguments: pointer to restore point object
|
|
//
|
|
// Returns: Win32 error code
|
|
//
|
|
// History: 14-Jun-2000 BrijeshK Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
DWORD CDataStore::SwitchRestorePoint(LONG_PTR pRestorePoint)
|
|
{
|
|
TENTER("CDataStore::SwitchRestorePoint");
|
|
|
|
CRestorePoint *prp = (CRestorePoint *) pRestorePoint;
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
INT64 llTemp;
|
|
|
|
if (prp)
|
|
{
|
|
//
|
|
// get the last restore point size - accurate
|
|
//
|
|
|
|
if (_llDataStoreUsageBytes != -1) // initialized
|
|
{
|
|
CHECKERR(CalculateRpUsage(prp,
|
|
&_llCurrentRpUsageBytes,
|
|
TRUE, // force calculation
|
|
FALSE), // everything
|
|
"CalculateRpUsage");
|
|
|
|
|
|
_llDataStoreUsageBytes += _llCurrentRpUsageBytes;
|
|
_llCurrentRpUsageBytes = 0;
|
|
}
|
|
}
|
|
|
|
//
|
|
// get the size of the current snapshot
|
|
//
|
|
|
|
if (_dwFlags & SR_DRIVE_SYSTEM)
|
|
{
|
|
CRestorePoint rpCur;
|
|
|
|
CHECKERR(GetCurrentRestorePoint(rpCur),
|
|
"GetCurrentRestorePoint");
|
|
|
|
CHECKERR(CalculateRpUsage(&rpCur,
|
|
&_llCurrentRpUsageBytes,
|
|
TRUE,
|
|
TRUE),
|
|
"CalculateRpUsage");
|
|
}
|
|
|
|
Err:
|
|
TLEAVE();
|
|
return dwErr;
|
|
}
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Functiion CDataStore::CountChangeLogs
|
|
//
|
|
// Synopsis: counts the number of change logs & saves the drive table
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns: Win32 error code
|
|
//
|
|
// History: 12-Apr-2000 HenryLee Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
DWORD CDataStore::CountChangeLogs (LONG_PTR pRestorePoint)
|
|
{
|
|
CRestorePoint *prp = (CRestorePoint *) pRestorePoint;
|
|
CFindFile ff;
|
|
WIN32_FIND_DATA *pwfd = new WIN32_FIND_DATA;
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
int iCount = -1;
|
|
CRestorePoint *pCurRp = NULL;
|
|
|
|
if (! pwfd)
|
|
{
|
|
dwErr = ERROR_OUTOFMEMORY;
|
|
goto Err;
|
|
}
|
|
|
|
if (prp == NULL)
|
|
{
|
|
pCurRp = new CRestorePoint;
|
|
if (! pCurRp)
|
|
{
|
|
dwErr = ERROR_OUTOFMEMORY;
|
|
goto Err;
|
|
}
|
|
|
|
dwErr = GetCurrentRestorePoint (*pCurRp);
|
|
if (dwErr != ERROR_SUCCESS)
|
|
{
|
|
if (_dwFlags & SR_DRIVE_SYSTEM)
|
|
goto Err;
|
|
|
|
// This drive has no current restore point
|
|
// It could have been re-formatted or placed in read-only mode
|
|
// So assume no change logs are available
|
|
dwErr = ERROR_SUCCESS;
|
|
}
|
|
else prp = pCurRp;
|
|
}
|
|
|
|
if (prp != NULL)
|
|
{
|
|
LPWSTR pwcsPath = new WCHAR[MAX_PATH];
|
|
if (! pwcsPath)
|
|
{
|
|
dwErr = ERROR_OUTOFMEMORY;
|
|
goto Err;
|
|
}
|
|
|
|
iCount = 0;
|
|
|
|
MakeRestorePath (pwcsPath, _pwszDrive, prp->GetDir());
|
|
lstrcatW (pwcsPath, L"\\");
|
|
lstrcatW (pwcsPath, s_cszChangeLogPrefix);
|
|
|
|
if (TRUE == ff._FindFirstFile (pwcsPath, s_cszChangeLogSuffix, pwfd,
|
|
FALSE, FALSE))
|
|
do
|
|
{
|
|
iCount++;
|
|
}
|
|
while (ff._FindNextFile (pwcsPath, s_cszChangeLogSuffix, pwfd));
|
|
|
|
delete [] pwcsPath;
|
|
}
|
|
|
|
dwErr = SetNumChangeLogs (iCount);
|
|
|
|
Err:
|
|
if (pCurRp)
|
|
delete pCurRp;
|
|
|
|
if (pwfd)
|
|
delete pwfd;
|
|
return dwErr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Functiion CDataStore::IsVolumeDeleted
|
|
//
|
|
// Synopsis: determines if this volume is no longer accessible
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns: TRUE if can be removed
|
|
//
|
|
// History: 12-Apr-2000 HenryLee Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL CDataStore::IsVolumeDeleted ()
|
|
{
|
|
WCHAR wszMount[MAX_PATH];
|
|
DWORD dwChars = 0;
|
|
DWORD dwFsFlags = 0;
|
|
|
|
tenter("CDataStore::IsVolumeDeleted");
|
|
|
|
// don't open the volume, since it could be locked for chkdsk
|
|
|
|
if (FALSE == GetVolumePathNamesForVolumeNameW (_pwszGuid,
|
|
wszMount,
|
|
MAX_PATH,
|
|
&dwChars ))
|
|
{
|
|
if (GetLastError() != ERROR_MORE_DATA)
|
|
{
|
|
_dwFlags &= ~SR_DRIVE_ACTIVE;
|
|
trace(0, "! GetVolumePathNamesForVolumeNameW : %ld", GetLastError());
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
if (L'\0' == wszMount[0]) // empty string, no mount point
|
|
{
|
|
_dwFlags &= ~SR_DRIVE_ACTIVE;
|
|
trace(0, "! Empty mountpoint");
|
|
return TRUE;
|
|
}
|
|
|
|
wszMount[MAX_PATH-1] = L'\0';
|
|
|
|
if (lstrlenW (wszMount) > MAX_MOUNTPOINT_PATH) // mountpoint too long
|
|
{
|
|
_dwFlags &= ~SR_DRIVE_ACTIVE;
|
|
trace(0, "! Mountpoint too long");
|
|
return TRUE;
|
|
}
|
|
|
|
// update the drive letter
|
|
lstrcpyW (_pwszDrive, wszMount); // copy the first string
|
|
|
|
if (GetVolumeNameForVolumeMountPoint (_pwszDrive, wszMount, MAX_PATH))
|
|
{
|
|
if (lstrcmpW (wszMount, _pwszGuid) != 0)
|
|
{
|
|
_dwFlags &= ~SR_DRIVE_ACTIVE;
|
|
trace(0, "! volume GUID changed");
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
GetVolumeInfo (); // get the latest volume flags if possible
|
|
|
|
trace(0, "volume %S is active", wszMount);
|
|
|
|
tleave();
|
|
return FALSE; // volume is still active
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Functiion CDataStore::GetNTName
|
|
//
|
|
// Synopsis: constructs the NT object name into a static buffer
|
|
//
|
|
// Arguments: (none) caller must take the datastore lock
|
|
//
|
|
// Returns: pointer to string
|
|
//
|
|
// History: 12-Apr-2000 HenryLee Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
WCHAR * CDataStore::GetNTName ()
|
|
{
|
|
NTSTATUS nts;
|
|
static WCHAR wcsBuffer [MAX_PATH];
|
|
|
|
wcsBuffer[0] = L'\0';
|
|
// Open a handle to the volume
|
|
HANDLE h = CreateFileW ( _pwszGuid,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_FLAG_BACKUP_SEMANTICS,
|
|
NULL );
|
|
|
|
if (h != INVALID_HANDLE_VALUE)
|
|
{
|
|
OBJECT_NAME_INFORMATION * poni;
|
|
poni = (OBJECT_NAME_INFORMATION *) wcsBuffer;
|
|
|
|
// Get name from NT namespace
|
|
nts = NtQueryObject (h, ObjectNameInformation, poni, MAX_PATH, NULL);
|
|
|
|
if (NT_SUCCESS(nts))
|
|
{
|
|
if (poni->Name.Length < MAX_PATH * sizeof(WCHAR))
|
|
poni->Name.Buffer [poni->Name.Length / sizeof(WCHAR) - 1] = TEXT('\0');
|
|
}
|
|
|
|
CloseHandle (h);
|
|
return poni->Name.Buffer;
|
|
}
|
|
else
|
|
{
|
|
return wcsBuffer;
|
|
}
|
|
|
|
}
|
|
|