/****************************************************************************** * * 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; } }