windows-nt/Source/XPSP1/NT/shell/osshell/dskquota/watchdog/stats.cpp
2020-09-26 16:20:57 +08:00

367 lines
13 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
{
//
// FEATURE: 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;
}