Windows2000/private/windows/shell/dskquota/watchdog/stats.cpp
2020-09-30 17:12:32 +02:00

267 lines
10 KiB
C++

/* File: stats.cpp
Description: These classes provide temporary storage of quota
information for a given volume/user pair. Creation of the object
automatically gathers the necessary quota and user information.
Clients then query the objects to retrieve quota statistics when
desired.
CStatistics
CStatisticsList
+----------+
+--->| CVolume |
| +----------+
+-----------------+ +-------------+<---+
| CStatisticsList |<-->>| CStatistics | contains
+-----------------+ +-------------+<---+
| +-------------+
+--->| CVolumeUser |
+-------------+
Revision History:
Date Description Programmer
-------- ----------- ----------
07/01/97 Initial creation. BrianAu
*/
#include <precomp.hxx>
#pragma hdrstop
#include "dskquota.h"
#include "stats.h"
// Gather quota statistics for a given volume-user pair.
CStatistics::CStatistics(TCHAR chVolLetter, LPCTSTR pszVolDisplayName, LPBYTE pUserSid) : m_vol(chVolLetter, pszVolDisplayName),
m_bQuotaEnabled(FALSE),
m_bWarnAtThreshold(FALSE),
m_bDenyAtLimit(FALSE),
m_bValid(FALSE)
{
// If the volume doesn't support quotas, no use in continuing with the expensive stuff.
if (m_vol.SupportsQuotas())
{
HRESULT hr;
hr = OleInitialize(NULL);
if (SUCCEEDED(hr))
{
// Load dskquota.dll, creating a new disk quota controller object.
IDiskQuotaControl *pQC;
hr = CoCreateInstance(CLSID_DiskQuotaControl, NULL, CLSCTX_INPROC_SERVER, IID_IDiskQuotaControl, (LPVOID *)&pQC);
if (SUCCEEDED(hr))
{
// Initialize the quota controller for this volume.
// We need only read access.
TCHAR szVolume[] = TEXT("X:\\");
szVolume[0] = m_vol.GetLetter();
hr = IDiskQuotaControl_Initialize(pQC, szVolume, GENERIC_READ);
if (SUCCEEDED(hr))
{
DWORD dwQuotaState = 0;
DWORD dwQuotaLogFlags = 0;
// Get the volume's quota state flags.
hr = pQC->GetQuotaState(&dwQuotaState);
if (SUCCEEDED(hr))
{
m_bQuotaEnabled = !DISKQUOTA_IS_DISABLED(dwQuotaState);
m_bDenyAtLimit = DISKQUOTA_IS_ENFORCED(dwQuotaState);
}
// Get the volume's quota logging flags.
hr = pQC->GetQuotaLogFlags(&dwQuotaLogFlags);
if (SUCCEEDED(hr))
{
m_bWarnAtThreshold = m_bQuotaEnabled && DISKQUOTA_IS_LOGGED_USER_THRESHOLD(dwQuotaLogFlags);
}
// Get the quota user object for the current user.
oleauto_ptr<IDiskQuotaUser> ptrUser;
hr = pQC->FindUserSid(pUserSid, ptrUser._getoutptr(), DISKQUOTA_USERNAME_RESOLVE_SYNC);
if (SUCCEEDED(hr))
{
// Get the user's account and friendly names.
TCHAR szUserName[MAX_PATH] = { TEXT('\0') };
TCHAR szUserDomain[MAX_PATH] = { TEXT('\0') };
TCHAR szUserAccount[MAX_PATH] = { TEXT('\0') };
TCHAR szUserEmailName[MAX_PATH] = { TEXT('\0') };
IDiskQuotaUser_GetName(ptrUser, szUserDomain, ARRAYSIZE(szUserDomain), szUserAccount, ARRAYSIZE(szUserAccount), szUserName, ARRAYSIZE(szUserName));
// Get the user's quota statistics for the volume.
DISKQUOTA_USER_INFORMATION dui;
hr = ptrUser->GetQuotaInformation((LPBYTE)&dui, sizeof(dui));
if (SUCCEEDED(hr))
{
// Make sure we didn't enumerate a non-existant user.
// This is because of the way NTFS enumerates quota records.
// Even if there is no record currently in the quota file, enumeration returns a record. This is consistent with
// automatic addition of users upon first write to the
// volume. We must check the quota information to determine if it's an active user.
if (((__int64)-2) != dui.QuotaLimit.QuadPart && (0 != dui.QuotaLimit.QuadPart || 0 != dui.QuotaThreshold.QuadPart || 0 != dui.QuotaUsed.QuadPart))
{
// Store user-specific info.
CString strUserDisplayName;
if (TEXT('\0') != szUserName[0])
{
// User has a "friendly" name associated
// with their account. Include it in the display
// name.
strUserDisplayName.Format(TEXT("%1\\%2 (%3)"), szUserDomain, szUserAccount, szUserName);
}
else
{
// No "friendly" name associated with user account.
strUserDisplayName.Format(TEXT("%1\\%2"), szUserDomain, szUserAccount, szUserName);
}
// Store the user's information in the volume-user object.
hr = m_volUser.SetUserInfo(strUserDisplayName, szUserEmailName, dui.QuotaThreshold, dui.QuotaLimit, dui.QuotaUsed);
if (FAILED(hr))
{
DebugMsg(DM_ERROR, TEXT("Error 0x%08X setting user info on volume \"%s\"."), hr, pszVolDisplayName);
}
m_bValid = SUCCEEDED(hr);
}
}
else
{
DebugMsg(DM_ERROR, TEXT("Error 0x%08X getting user quota info on volume \"%s\"."), hr, pszVolDisplayName);
}
}
else
{
DebugMsg(DM_ERROR, TEXT("Error 0x%08X finding quota user on volume \"%s\"."), hr, pszVolDisplayName);
}
}
else
{
DebugMsg(DM_ERROR, TEXT("Error 0x%08X initializing QC for volume \"%s\"."), hr, pszVolDisplayName);
}
pQC->ShutdownAndRelease(TRUE);
} // if SUCCEEDED(CoCreateInstance())
else
DebugMsg(DM_ERROR, TEXT("Failed CoCreateInstance. 0x%08X"), hr);
OleUninitialize();
} // if SUCCEEDED(OleInitialize())
else
DebugMsg(DM_ERROR, TEXT("Failed OleInitialize. 0x%08X"), hr);
} // if m_vol.SupportsQuotas()
else
DebugMsg(DM_ERROR, TEXT("Volume \"%s\" doesn't support quotas."), pszVolDisplayName);
}
// Determine if a specific statistics object contains statistics that
// will generate either an email notification or a popup notification.
BOOL CStatistics::IncludeInReport(VOID) const
{
BOOL bReport = FALSE;
// First check data validity and volume settings.
if (IsValid() && // Does volume support quotas and was vol opened?
QuotasEnabled() && // Are quotas enabled on the volume?
WarnAtThreshold()) // Is the "warn at threshold" bit set on the vol?
{
// Now see if user's quota usage warrants reporting.
// Report if AmtUsed > Threshold.
if (GetUserQuotaUsed().QuadPart > GetUserQuotaThreshold().QuadPart)
{
bReport = TRUE;
}
}
return bReport;
}
CStatisticsList::CStatisticsList(VOID)
{
// Nothing to do.
}
CStatisticsList::~CStatisticsList(VOID)
{
INT cEntries = m_List.Count();
for (INT i = 0; i < cEntries; i++)
{
delete m_List[i];
}
m_List.Clear();
}
const CStatistics * CStatisticsList::GetEntry(INT iEntry)
{
return m_List[iEntry];
}
HRESULT CStatisticsList::AddEntry(TCHAR chVolLetter, LPCTSTR pszVolDisplayName, LPBYTE pUserSid)
{
HRESULT hr = E_OUTOFMEMORY;
CStatistics *pStats = NULL;
// Create a new statistics object.
// The ctor will fill in the volume and user information.
pStats = new CStatistics(chVolLetter, pszVolDisplayName, pUserSid);
if (NULL != pStats)
{
if (pStats->IsValid())
{
BOOL bDuplicate = FALSE;
// Look for a duplicate. Shouldn't be one but just to make sure.
INT cEntries = m_List.Count();
for (INT i = 0; i < cEntries; i++)
{
const CStatistics *pEntry = m_List[i];
if (pStats->SameVolume(*pEntry))
bDuplicate = TRUE;
}
if (!bDuplicate)
{
hr = S_OK;
try
{
m_List.Append(pStats);
}
catch(OutOfMemory)
{
DebugMsg(DM_ERROR, TEXT("CStatisticsList::AddEntry - Insufficient memory."));
hr = E_OUTOFMEMORY;
}
}
else
{
// BUGBUG: We should really assert here.
DebugMsg(DM_ERROR, TEXT("CStatisticsList::AddEntry - Duplicate entry found."));
hr = S_FALSE;
}
}
else
{
// Stats object is invalid. Probably because the volume doesn't support quotas.
DebugMsg(DM_ERROR, TEXT("CStatisticsList::AddEntry - Volume stats not valid."));
hr = S_FALSE;
}
}
if (S_OK != hr)
{
// CStatistics object wasn't added to the list.
// Probably was a duplicate (shouldn't happen) or the volume
// didn't support quotas.
delete pStats;
}
return hr;
}