1342 lines
41 KiB
C++
1342 lines
41 KiB
C++
///////////////////////////////////////////////////////////////////////////////
|
|
/* File: enumuser.cpp
|
|
|
|
Description: Contains member function definitions for class DiskQuotaUserEnum.
|
|
The DiskQuotaUserEnum object is provided to enumerate the users in a
|
|
volume's quota information file. The caller instantiates an enumerator
|
|
through IDiskQuotaControl::CreateDiskQuotaUserEnum(). The enumerator's
|
|
interface IEnumDiskQuotaUsers supports the normal OLE 2 enumeration
|
|
functions Next(), Skip(), Reset() and Clone().
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
05/22/96 Initial creation. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
#include "pch.h" // PCH
|
|
#pragma hdrstop
|
|
|
|
#include "user.h"
|
|
#include "userenum.h"
|
|
|
|
//
|
|
// Verify that build is UNICODE.
|
|
//
|
|
#if !defined(UNICODE)
|
|
# error This module must be compiled UNICODE.
|
|
#endif
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: DiskQuotaUserEnum::DiskQuotaUserEnum
|
|
|
|
Description: Constructor.
|
|
|
|
Arguments:
|
|
pFSObject - Pointer to an existing "file system" object.
|
|
It is through this object that the enumerator accesses the ntioapi
|
|
functions. A pointer to this file system object is also passed
|
|
on to contained user objects so they may refresh their data when
|
|
required.
|
|
|
|
pQuotaController - Pointer to an IDiskQuotaControl interface that we'll
|
|
AddRef(). The control object is who provides the "name changed"
|
|
notification mechanism. It needs to stay around as long as the
|
|
enumerator is alive.
|
|
|
|
pSidNameResolver - Pointer to an ISidNameResolver interface that will
|
|
be used to resolve user SIDs to account names. The resolver object
|
|
is initially instantiated by the quota controller.
|
|
|
|
Returns: Nothing.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
05/22/96 Initial creation. BrianAu
|
|
08/15/97 Moved pQuotaControl, pSidNameResolver and pFSObject BrianAu
|
|
arguments from Initialize() to ctor. Needed so
|
|
that ref counting is correct.
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
DiskQuotaUserEnum::DiskQuotaUserEnum(
|
|
PDISKQUOTA_CONTROL pQuotaController,
|
|
PSID_NAME_RESOLVER pSidNameResolver,
|
|
FSObject *pFSObject
|
|
) : m_cRef(0),
|
|
m_pbBuffer(NULL),
|
|
m_pbCurrent(NULL),
|
|
m_cbBuffer(0),
|
|
m_pSidList(NULL),
|
|
m_cbSidList(0),
|
|
m_bEOF(FALSE),
|
|
m_bSingleUser(FALSE),
|
|
m_bInitialized(FALSE),
|
|
m_bRestartScan(TRUE),
|
|
m_fNameResolution(DISKQUOTA_USERNAME_RESOLVE_NONE),
|
|
m_pFSObject(pFSObject),
|
|
m_pQuotaController(pQuotaController),
|
|
m_pSidNameResolver(pSidNameResolver)
|
|
{
|
|
DBGTRACE((DM_USER, DL_HIGH, TEXT("DiskQuotaUserEnum::DiskQuotaUserEnum")));
|
|
|
|
if (NULL != m_pQuotaController)
|
|
m_pQuotaController->AddRef();
|
|
|
|
if (NULL != m_pSidNameResolver)
|
|
m_pSidNameResolver->AddRef();
|
|
|
|
if (NULL != m_pFSObject)
|
|
m_pFSObject->AddRef();
|
|
|
|
InterlockedIncrement(&g_cRefThisDll);
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: DiskQuotaUserEnum::~DiskQuotaUserEnum
|
|
|
|
Description: Destructor. Destroys the enumerator's internal buffers and
|
|
releases any held interface pointers.
|
|
|
|
Arguments: None.
|
|
|
|
Returns: Nothing.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
05/22/96 Initial creation. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
DiskQuotaUserEnum::~DiskQuotaUserEnum(void)
|
|
{
|
|
DBGTRACE((DM_USER, DL_HIGH, TEXT("DiskQuotaUserEnum::~DiskQuotaUserEnum")));
|
|
|
|
if (NULL != m_pFSObject)
|
|
m_pFSObject->Release();
|
|
|
|
//
|
|
// Order is important here. Release the resolver before the controller.
|
|
//
|
|
if (NULL != m_pSidNameResolver)
|
|
m_pSidNameResolver->Release();
|
|
|
|
if (NULL != m_pQuotaController)
|
|
m_pQuotaController->Release();
|
|
|
|
delete [] m_pbBuffer;
|
|
delete [] m_pSidList;
|
|
|
|
InterlockedDecrement(&g_cRefThisDll);
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: DiskQuotaUserEnum::QueryInterface
|
|
|
|
Description: Obtain pointer to IUnknown or IEnumDiskQuotaUser. Note that
|
|
referenced object is uninitialized. Recipient of interface pointer
|
|
must call Initialize() member function before object is usable.
|
|
|
|
Arguments:
|
|
riid - Reference to requested interface ID. IID_IUnknown and
|
|
IID_IEnumDiskQuotaUser are recognized.
|
|
|
|
ppvOut - Address of interface pointer variable to accept the
|
|
returned interface pointer.
|
|
|
|
Returns:
|
|
NO_ERROR - Success.
|
|
E_NOINTERFACE - Requested interface not supported.
|
|
E_INVALIDARG - ppvOut argument is NULL.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
05/22/96 Initial creation. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP
|
|
DiskQuotaUserEnum::QueryInterface(
|
|
REFIID riid,
|
|
LPVOID *ppvOut
|
|
)
|
|
{
|
|
HRESULT hResult = E_NOINTERFACE;
|
|
|
|
if (NULL == ppvOut)
|
|
return E_INVALIDARG;
|
|
|
|
*ppvOut = NULL;
|
|
|
|
if (IID_IUnknown == riid || IID_IEnumDiskQuotaUsers == riid)
|
|
{
|
|
//
|
|
// Interface supported.
|
|
//
|
|
*ppvOut = this;
|
|
((LPUNKNOWN)*ppvOut)->AddRef();
|
|
hResult = NOERROR;
|
|
}
|
|
|
|
return hResult;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: DiskQuotaUserEnum::AddRef
|
|
|
|
Description: Increments object reference count.
|
|
|
|
Arguments: None.
|
|
|
|
Returns: New reference count value.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
05/22/96 Initial creation. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP_(ULONG)
|
|
DiskQuotaUserEnum::AddRef(
|
|
VOID
|
|
)
|
|
{
|
|
ULONG ulReturn = m_cRef + 1;
|
|
|
|
DBGPRINT((DM_COM, DL_HIGH, TEXT("DiskQuotaUserEnum::AddRef, 0x%08X %d -> %d"),
|
|
this, ulReturn - 1, ulReturn));
|
|
|
|
InterlockedIncrement(&m_cRef);
|
|
|
|
return ulReturn;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: DiskQuotaUserEnum::Release
|
|
|
|
Description: Decrements object reference count. If count drops to 0,
|
|
object is deleted.
|
|
|
|
Arguments: None.
|
|
|
|
Returns: New reference count value.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
05/22/96 Initial creation. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP_(ULONG)
|
|
DiskQuotaUserEnum::Release(
|
|
VOID
|
|
)
|
|
{
|
|
ULONG ulReturn = m_cRef - 1;
|
|
|
|
DBGPRINT((DM_COM, DL_HIGH, TEXT("DiskQuotaUserEnum::Release, 0x%08X %d -> %d"),
|
|
this, ulReturn + 1, ulReturn));
|
|
|
|
if (InterlockedDecrement(&m_cRef) == 0)
|
|
{
|
|
delete this;
|
|
ulReturn = 0;
|
|
}
|
|
return ulReturn;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: DiskQuotaUserEnum::Initialize
|
|
|
|
Description: Initializes a new enumerator object.
|
|
This member function is overloaded to provide two
|
|
implementations. The first accepts explicit arguments for
|
|
initialization. This member is intended for creating a new unique
|
|
enumerator through IDiskQuotaControl::CreateEnumUsers. The
|
|
second implementation merely accepts a reference to an existing
|
|
EnumUsers object. This member is intended to support the function
|
|
IEnumDiskQuotaUser::Clone().
|
|
|
|
Arguments:
|
|
fNameResolution - Method of SID-to-name resolution. Can be one of the
|
|
following:
|
|
DISKQUOTA_USERNAME_RESOLVE_NONE
|
|
DISKQUOTA_USERNAME_RESOLVE_SYNC
|
|
DISKQUOTA_USERNAME_RESOLVE_ASYNC
|
|
|
|
cbBuffer [optional] - Size in bytes of the internal buffer used in
|
|
calls to the NTIOAPI functions. Default is ENUMUSER_BUF_LEN.
|
|
|
|
rgpSids [optional] - Pointer to a list of SID pointers. If
|
|
provided, only those users with SIDs included in the list are
|
|
returned. This argument may be NULL in which case ALL users are
|
|
included. Any element containing a NULL pointer will terminate
|
|
the list.
|
|
|
|
cpSids [optional] - If pSidList is not NULL, this arg contains
|
|
the count of entries in rgpSids. If rgpSids is not NULL and this
|
|
argument contains 0, rgpSids is assumed to contain a terminating
|
|
NULL pointer entry.
|
|
|
|
UserEnum - Reference to an existing DiskQuotaUserEnum object. The new
|
|
object opens a connection to the same volume as the object being
|
|
cloned. The new object maintains a separate buffer for transfer
|
|
of data from the NTIOAPI system.
|
|
|
|
Returns:
|
|
NO_ERROR - Success.
|
|
S_FALSE - Already initialized.
|
|
E_OUTOFMEMORY - Insufficient memory.
|
|
ERROR_INVALID_SID (hr) - A SID in rgpSids was invalid.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
05/22/96 Initial creation. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
DiskQuotaUserEnum::Initialize(
|
|
DWORD fNameResolution,
|
|
DWORD cbBuffer,
|
|
PSID *rgpSids,
|
|
DWORD cpSids
|
|
)
|
|
{
|
|
HRESULT hResult = NO_ERROR;
|
|
|
|
if (m_bInitialized)
|
|
{
|
|
hResult = S_FALSE;
|
|
}
|
|
else
|
|
{
|
|
try
|
|
{
|
|
//
|
|
// Create an internal buffer for data transfer from the ntioapi.
|
|
//
|
|
m_pbBuffer = new BYTE [cbBuffer];
|
|
|
|
m_cbBuffer = cbBuffer;
|
|
|
|
if (NULL != rgpSids)
|
|
{
|
|
//
|
|
// A list of SID pointers was provided.
|
|
// Initialize the SID list structure.
|
|
// Can throw OutOfMemory.
|
|
//
|
|
m_bSingleUser = (cpSids == 1);
|
|
hResult = InitializeSidList(rgpSids, cpSids);
|
|
}
|
|
|
|
if (SUCCEEDED(hResult))
|
|
{
|
|
//
|
|
// Must have an independent instance of the controller's file system
|
|
// object. The NTIOAPI functions maintain an enumeration context
|
|
// for each open handle. Therefore, each user enumerator must have a
|
|
// unique file handle to the NTIOAPI object.
|
|
// I say this because it appears tempting to just keep a copy of the
|
|
// controller's FSObject pointer and AddRef it.
|
|
//
|
|
// This create-n-swap is sort of slimy. We originally got a
|
|
// ptr to the caller's FSObject in the ctor. However, now we want
|
|
// to create our own FSObject. Create a copy and release the original.
|
|
//
|
|
FSObject *pFsoTemp = m_pFSObject;
|
|
m_pFSObject = NULL;
|
|
hResult = FSObject::Create(*pFsoTemp, &m_pFSObject);
|
|
pFsoTemp->Release();
|
|
|
|
if (SUCCEEDED(hResult))
|
|
{
|
|
m_fNameResolution = fNameResolution;
|
|
m_bInitialized = TRUE;
|
|
}
|
|
}
|
|
}
|
|
catch(CAllocException& e)
|
|
{
|
|
hResult = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
|
|
return hResult;
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
DiskQuotaUserEnum::Initialize(
|
|
const DiskQuotaUserEnum& UserEnum
|
|
)
|
|
{
|
|
HRESULT hResult = NO_ERROR;
|
|
|
|
try
|
|
{
|
|
//
|
|
// Initialize the new enumerator without a SID list.
|
|
// If the enumerator being copied has a SID list, we
|
|
// don't want to re-create a list of SID pointers for Initialize()
|
|
// so we defer this for InitializeSidList. InitializeSidList
|
|
// has an overloaded version that accepts a pointer to an existing
|
|
// SIDLIST structure and merely copies the bytes.
|
|
//
|
|
hResult = Initialize(UserEnum.m_fNameResolution,
|
|
UserEnum.m_cbBuffer,
|
|
NULL,
|
|
0);
|
|
|
|
if (SUCCEEDED(hResult) && NULL != UserEnum.m_pSidList)
|
|
{
|
|
m_bSingleUser = UserEnum.m_bSingleUser;
|
|
hResult = InitializeSidList(UserEnum.m_pSidList,
|
|
UserEnum.m_cbSidList);
|
|
}
|
|
}
|
|
catch(CAllocException& e)
|
|
{
|
|
hResult = E_OUTOFMEMORY;
|
|
}
|
|
return hResult;
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: DiskQuotaUserEnum::InitializeSidList
|
|
|
|
Description: Initializes the m_pSidList member of the enumerator.
|
|
The method comes in two overloaded forms. The first accepts a pointer
|
|
to an existing SIDLIST structure and merely creates a new copy.
|
|
The second form accepts the address of an array of SID pointers and
|
|
generates a new SIDLIST structure.
|
|
|
|
Arguments:
|
|
pSidList - Address of an existing SIDLIST structure to be copied.
|
|
|
|
cbSidList - Number of bytes in the SIDLIST structure.
|
|
|
|
rgpSids - Pointer to a list of SID pointers. If provided, only those
|
|
users with SIDs included in the list are returned. This argument
|
|
may be NULL in which case ALL users are included. Any element
|
|
containing a NULL pointer will terminate the list.
|
|
|
|
cpSids - If pSidList is not NULL, this arg contains the count of
|
|
entries in rgpSids. If rgpSids is not NULL and this argument
|
|
contains 0, rgpSids is assumed to contain a terminating NULL
|
|
pointer entry.
|
|
|
|
Returns:
|
|
NO_ERROR - Success.
|
|
ERROR_INVALID_SID (hr) - A SID in rgpSids was invalid.
|
|
|
|
Exceptions: OutOfMemory.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
08/13/96 Initial creation. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
DiskQuotaUserEnum::InitializeSidList(
|
|
PSIDLIST pSidList,
|
|
DWORD cbSidList
|
|
)
|
|
{
|
|
HRESULT hResult = NO_ERROR;
|
|
|
|
DBGASSERT((NULL != pSidList));
|
|
DBGASSERT((0 < cbSidList));
|
|
|
|
//
|
|
// Create a buffer for the SID list copy.
|
|
//
|
|
m_pSidList = (PSIDLIST)new BYTE[cbSidList];
|
|
|
|
//
|
|
// Copy the enumerator's SID list.
|
|
//
|
|
CopyMemory(m_pSidList, pSidList, cbSidList);
|
|
m_cbSidList = cbSidList;
|
|
|
|
return hResult;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
DiskQuotaUserEnum::InitializeSidList(
|
|
PSID *rgpSids,
|
|
DWORD cpSids
|
|
)
|
|
{
|
|
HRESULT hResult = NO_ERROR;
|
|
|
|
DBGASSERT((NULL != rgpSids));
|
|
DBGASSERT((0 < cpSids));
|
|
|
|
//
|
|
// Create a SIDLIST structure from the array of SID pointers.
|
|
// Can throw OutOfMemory.
|
|
//
|
|
hResult = CreateSidList(rgpSids, cpSids, &m_pSidList, &m_cbSidList);
|
|
|
|
if (FAILED(hResult))
|
|
{
|
|
DBGASSERT((NULL == m_pSidList));
|
|
DBGASSERT((0 == m_cbSidList));
|
|
}
|
|
|
|
return hResult;
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: DiskQuotaUserEnum::QueryQuotaInformation
|
|
|
|
Description: Provides a simple wrapper around the NTIOAPI function
|
|
QueryQuotaInformationFile. The function adds value by providing
|
|
the address and size of the enumerator's data buffer.
|
|
Note that the QueryQuotaInformationFile interface in NTIOAPI
|
|
functions as an enumerator itself. Repeated calls enumerate
|
|
user quota data much the same way the Next() function does in an OLE
|
|
enumerator interface. Data is returned in a byte buffer as a series
|
|
of variable-length quota records.
|
|
|
|
Arguments:
|
|
bReturnSingleEntry [optional] - TRUE if only a single entry is
|
|
desired. FALSE if multiple records are desired. Default is
|
|
FALSE.
|
|
|
|
pSidList [optional] - Pointer to a list of SIDs. If provided, the
|
|
data returned is only for those users included in the SID list.
|
|
Default is NULL.
|
|
|
|
cbSidList [optional] - If SidList is not NULL, contains length
|
|
of SidList in bytes. Default is 0.
|
|
|
|
pStartSid [optional] - Pointer to SID in SID list where scan is to
|
|
start if bRestartScan is TRUE. Default is NULL.
|
|
|
|
bRestartScan [optional] - TRUE = restart enumeration at first user
|
|
or user pointed to by StartSid in SidList (if provided).
|
|
FALSE = continue enumeration from current point.
|
|
Default is FALSE.
|
|
|
|
Returns:
|
|
NO_ERROR - Success.
|
|
ERROR_NO_MORE_ITEMS - No more user records.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
05/22/96 Initial creation. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
DiskQuotaUserEnum::QueryQuotaInformation(
|
|
BOOL bReturnSingleEntry,
|
|
PVOID pSidList,
|
|
ULONG cbSidList,
|
|
PSID pStartSid,
|
|
BOOL bRestartScan
|
|
)
|
|
{
|
|
HRESULT hResult = NO_ERROR;
|
|
|
|
if (bRestartScan)
|
|
{
|
|
//
|
|
// Reset EOF flag if restarting enumerator scan.
|
|
//
|
|
m_bEOF = FALSE;
|
|
}
|
|
|
|
if (!m_bEOF)
|
|
{
|
|
ZeroMemory(m_pbBuffer, m_cbBuffer);
|
|
|
|
hResult = m_pFSObject->QueryUserQuotaInformation(
|
|
m_pbBuffer,
|
|
m_cbBuffer,
|
|
bReturnSingleEntry,
|
|
pSidList,
|
|
cbSidList,
|
|
pStartSid,
|
|
bRestartScan);
|
|
|
|
if (ERROR_SUCCESS == HRESULT_CODE(hResult) || ERROR_NO_MORE_ITEMS == HRESULT_CODE(hResult))
|
|
{
|
|
//
|
|
// The enumeration logic changed between Win2000 and WinXP.
|
|
// On Win2000, NTFS will return ERROR_NO_MORE_ITEMS on the last
|
|
// buffer returned that contains data. On WinXP, this error
|
|
// code is returned on the first buffer that returns NO data.
|
|
// To handle both cases, we zero out the buffer before reading data
|
|
// and inspect the SidLength value in the first record to determine
|
|
// if the buffer contains any data. If the sid length is 0, we
|
|
// can assume the buffer is empty.
|
|
//
|
|
hResult = NO_ERROR;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// There REALLY are no more entries.
|
|
//
|
|
hResult = HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS);
|
|
}
|
|
return hResult;
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: DiskQuotaUserEnum::CreateUserObject
|
|
|
|
Description: Creates a new DiskQuotaUser object from the quota information
|
|
retrieved through QueryQuotaInformation. The caller provides a pointer
|
|
to the start of the desired quota info record to be used for
|
|
initialization.
|
|
|
|
Arguments:
|
|
pfqi - Pointer to the quota information record used for initialization.
|
|
|
|
ppOut - Address of interface pointer variable to accept the user object's
|
|
IDiskQuotaUser interface pointer.
|
|
|
|
Returns:
|
|
NO_ERROR - Success.
|
|
E_INVALIDARG - pfqi or ppOut arg is NULL.
|
|
E_UNEXPECTED - Unexpected error.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
05/22/96 Initial creation. BrianAu
|
|
09/05/96 Added exception handling. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
DiskQuotaUserEnum::CreateUserObject(
|
|
PFILE_QUOTA_INFORMATION pfqi,
|
|
PDISKQUOTA_USER *ppOut
|
|
)
|
|
{
|
|
HRESULT hResult = NO_ERROR;
|
|
|
|
if (NULL == pfqi || NULL == ppOut)
|
|
return E_INVALIDARG;
|
|
|
|
//
|
|
// Create the user object and get the IDiskQuotaUser interface pointer.
|
|
// This pointer is what is given to the caller.
|
|
//
|
|
m_pFSObject->AddRef();
|
|
DiskQuotaUser *pUser = new DiskQuotaUser(m_pFSObject);
|
|
|
|
//
|
|
// Initialize the new user object using the buffered quota data pointed to
|
|
// by pfqi.
|
|
//
|
|
hResult = pUser->Initialize(pfqi);
|
|
|
|
if (SUCCEEDED(hResult))
|
|
{
|
|
hResult = pUser->QueryInterface(IID_IDiskQuotaUser, (LPVOID *)ppOut);
|
|
}
|
|
|
|
if (FAILED(hResult))
|
|
{
|
|
//
|
|
// Either Initialize or QueryInterface failed. Delete the object.
|
|
//
|
|
delete pUser;
|
|
pUser = NULL;
|
|
}
|
|
|
|
return hResult;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: DiskQuotaUserEnum::GetNextUser
|
|
|
|
Description: Creates a new user object from the "current" record in the
|
|
quota information buffer. A pointer to the object's IDiskQuotaUser
|
|
interface is returned and the "current" record pointer in the
|
|
quota information buffer is advanced to the next user record.
|
|
|
|
Arguments:
|
|
ppOut [optional] - Address of interface pointer variable to receive
|
|
address of user object's IDiskQuotaUserInterface pointer. If this
|
|
argument is NULL, the new user object is not created. This is
|
|
useful for skipping items in the enumeration.
|
|
|
|
Returns:
|
|
NO_ERROR - Success.
|
|
E_DISKQUOTA_INVALID_SID - User record's SID is invalid.
|
|
ERROR_NO_MORE_ITEMS - No more users.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
05/22/96 Initial creation. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
DiskQuotaUserEnum::GetNextUser(
|
|
PDISKQUOTA_USER *ppOut
|
|
)
|
|
{
|
|
PFILE_QUOTA_INFORMATION pfqi = (PFILE_QUOTA_INFORMATION)m_pbCurrent;
|
|
HRESULT hResult = NO_ERROR;
|
|
|
|
//
|
|
// If m_pbCurrent is NULL, this is the first request for data.
|
|
// If pfqi->NextEntryOffset is 0, we need to read another buffer of data.
|
|
//
|
|
if (NULL == m_pbCurrent)
|
|
{
|
|
//
|
|
// No more user entries in buffer.
|
|
// Read quota information into m_pbBuffer.
|
|
// Use SID list if we have one.
|
|
//
|
|
hResult = QueryQuotaInformation(m_bSingleUser, // Single user?
|
|
m_pSidList, // SID list.
|
|
m_cbSidList, // SID list length.
|
|
0, // Start SID,
|
|
m_bRestartScan); // Restart scan?
|
|
if (SUCCEEDED(hResult))
|
|
{
|
|
//
|
|
// New information in buffer. Reset record pointers.
|
|
//
|
|
m_pbCurrent = m_pbBuffer;
|
|
m_bRestartScan = FALSE;
|
|
pfqi = (PFILE_QUOTA_INFORMATION)m_pbCurrent;
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hResult))
|
|
{
|
|
//
|
|
// We have a valid pointer into the buffer of user quota data.
|
|
//
|
|
if (NULL != ppOut)
|
|
{
|
|
if (0 != pfqi->SidLength)
|
|
{
|
|
//
|
|
// Caller provided a user interface pointer variable.
|
|
// Create a new user record. This can throw OutOfMemory.
|
|
//
|
|
hResult = CreateUserObject(pfqi, ppOut);
|
|
}
|
|
else
|
|
{
|
|
m_bEOF = TRUE;
|
|
hResult = HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS);
|
|
}
|
|
}
|
|
|
|
if (0 != pfqi->NextEntryOffset)
|
|
m_pbCurrent += pfqi->NextEntryOffset; // Advance to next user.
|
|
else
|
|
m_pbCurrent = NULL; // Reset to trigger quota file read.
|
|
|
|
}
|
|
return hResult;
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: DiskQuotaUserEnum::Next
|
|
|
|
Description: Retrieve the next cUsers records from the volume's quota
|
|
information file. If the enumerator was created with a SidList,
|
|
only those users contained in the SidList are included in the
|
|
enumeration. Repeated calls to Next() continue to enumerate
|
|
successive quota users. The Reset() function may be used to
|
|
reset the enumerator to the start of the enumeration.
|
|
|
|
Arguments:
|
|
cUsers - Number of elements in paUsers array.
|
|
|
|
pUser - Array of IDiskQuotaUser pointers. Must provide space for
|
|
cUsers pointers. Upon return, each element of this array contains
|
|
an interface pointer to a DiskQuotaUser object.
|
|
|
|
pcCreated [optional] - Address of DWORD to accept the count of user
|
|
object interface pointers returned in pUser. Note that any
|
|
array locations equal to or beyond the value returned in
|
|
pcCreated are invalid and set to NULL.
|
|
|
|
Returns:
|
|
S_OK - Success. Enumerated number of requested users.
|
|
S_FALSE - End of enumeration encountered. Returning less than
|
|
cUsers records.
|
|
E_INVALIDARG - pUser arg is NULL.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
05/22/96 Initial creation. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
DiskQuotaUserEnum::Next(
|
|
DWORD cUsers, // Number of elements in array.
|
|
PDISKQUOTA_USER *pUser, // Dest array for quota user interface ptrs.
|
|
DWORD *pcCreated // Return number created.
|
|
)
|
|
{
|
|
HRESULT hResult = S_OK;
|
|
UINT i = 0; // Index into user caller's array.
|
|
UINT cCreated = 0;
|
|
|
|
if (NULL == pUser)
|
|
return E_INVALIDARG;
|
|
|
|
if (NULL != pcCreated)
|
|
*pcCreated = 0;
|
|
|
|
try
|
|
{
|
|
IDiskQuotaUser *pNextUser = NULL; // Ptr to new user.
|
|
|
|
//
|
|
// Enumerate user records until one of the following:
|
|
// 1. Failure.
|
|
// 2. No more users.
|
|
// 3. Enumerated requested count.
|
|
//
|
|
while(SUCCEEDED(hResult) && cUsers > 0)
|
|
{
|
|
//
|
|
// Create new user object. This can throw OutOfMemory.
|
|
//
|
|
hResult = GetNextUser(&pNextUser);
|
|
if (SUCCEEDED(hResult))
|
|
{
|
|
//
|
|
// User records come from the quota file containing only a SID.
|
|
// We must ask the SidNameResolver to locate the corresponding
|
|
// account name. If client wants names synchronously, we block
|
|
// here until account name is found. User object will contain
|
|
// account name.
|
|
// If client wants names asynchronously, the user object is handed
|
|
// off to the resolver for background processing. We continue on.
|
|
// If the client implemented the IDiskQuotaEvents interface and
|
|
// called IConnectionPoint::Advise, it will receive a
|
|
// OnUserNameChange notification when the name is finally resolved.
|
|
// If user doesn't want user name resolved, don't do either.
|
|
// This would be the case if the client already has the SID/Name
|
|
// pair and just wants user objects.
|
|
//
|
|
switch(m_fNameResolution)
|
|
{
|
|
case DISKQUOTA_USERNAME_RESOLVE_ASYNC:
|
|
m_pSidNameResolver->FindUserNameAsync(pNextUser);
|
|
break;
|
|
case DISKQUOTA_USERNAME_RESOLVE_SYNC:
|
|
m_pSidNameResolver->FindUserName(pNextUser);
|
|
break;
|
|
case DISKQUOTA_USERNAME_RESOLVE_NONE:
|
|
default:
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Note: Ref count for pUser already incremented in
|
|
// DiskQuotaUser::QueryInterface.
|
|
//
|
|
*pUser = pNextUser;
|
|
pUser++;
|
|
cUsers--;
|
|
cCreated++;
|
|
}
|
|
}
|
|
|
|
if (NULL != pcCreated)
|
|
*pcCreated = cCreated; // If requested, return number of users created.
|
|
|
|
if (cUsers > 0)
|
|
{
|
|
//
|
|
// Less than requested number of users were retrieved.
|
|
//
|
|
hResult = S_FALSE;
|
|
while(cUsers > 0)
|
|
{
|
|
//
|
|
// Set any un-filled array elements to NULL.
|
|
//
|
|
*pUser = NULL;
|
|
pUser++;
|
|
cUsers--;
|
|
}
|
|
}
|
|
}
|
|
catch(CAllocException& e)
|
|
{
|
|
hResult = E_OUTOFMEMORY;
|
|
}
|
|
|
|
if (FAILED(hResult))
|
|
{
|
|
//
|
|
// Release any user objects already created.
|
|
//
|
|
for (i = 0; i < cCreated; i++)
|
|
{
|
|
PDISKQUOTA_USER pu = *(pUser + i);
|
|
if (NULL != pu)
|
|
{
|
|
pu->Release();
|
|
*(pUser + i) = NULL;
|
|
}
|
|
}
|
|
|
|
*pcCreated = 0;
|
|
}
|
|
|
|
return hResult;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: DiskQuotaUserEnum::Skip
|
|
|
|
Description: Skips a specified number of users in the user enumeration.
|
|
|
|
Arguments:
|
|
cUsers - Number of users to skip.
|
|
|
|
Returns:
|
|
S_OK - Success. Skipped number of requested users.
|
|
S_FALSE - End of enumeration encountered. Skipped less than
|
|
cUsers records.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
05/22/96 Initial creation. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
DiskQuotaUserEnum::Skip(
|
|
DWORD cUsers
|
|
)
|
|
{
|
|
while(cUsers > 0 && SUCCEEDED(GetNextUser(NULL)))
|
|
{
|
|
cUsers--;
|
|
}
|
|
|
|
return cUsers == 0 ? S_OK : S_FALSE;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: DiskQuotaUserEnum::Reset
|
|
|
|
Description: Resets the enumerator object so that the next call to Next()
|
|
starts enumerating at the beginning of the enumeration.
|
|
|
|
Arguments: None.
|
|
|
|
Returns:
|
|
Always returns S_OK.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
05/22/96 Initial creation. BrianAu
|
|
02/09/99 Changed so we just reset m_pbCurrent and BrianAu
|
|
m_bRestartScan.
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP
|
|
DiskQuotaUserEnum::Reset(
|
|
VOID
|
|
)
|
|
{
|
|
m_pbCurrent = NULL;
|
|
m_bRestartScan = TRUE;
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: DiskQuotaUserEnum::Clone
|
|
|
|
Description: Creates a duplicate of the enumerator object and returns
|
|
a pointer to the new object's IEnumDiskQuotaUser interface.
|
|
|
|
Arguments:
|
|
ppOut - Address of interface pointer variable to accept the pointer
|
|
to the new object's IEnumDiskQuotaUser interface.
|
|
|
|
Returns:
|
|
NO_ERROR - Success.
|
|
E_OUTOFMEMORY - Insufficient memory to create new enumerator.
|
|
E_INVALIDARG - ppOut arg was NULL.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
05/22/96 Initial creation. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP
|
|
DiskQuotaUserEnum::Clone(
|
|
PENUM_DISKQUOTA_USERS *ppOut
|
|
)
|
|
{
|
|
HRESULT hResult = NO_ERROR;
|
|
|
|
if (NULL == ppOut)
|
|
return E_INVALIDARG;
|
|
|
|
try
|
|
{
|
|
DiskQuotaUserEnum *pUserEnum = new DiskQuotaUserEnum(
|
|
m_pQuotaController,
|
|
m_pSidNameResolver,
|
|
m_pFSObject);
|
|
|
|
hResult = pUserEnum->Initialize(*this);
|
|
|
|
if (SUCCEEDED(hResult))
|
|
{
|
|
hResult = pUserEnum->QueryInterface(IID_IEnumDiskQuotaUsers,
|
|
(LPVOID *)ppOut);
|
|
}
|
|
|
|
if (FAILED(hResult))
|
|
{
|
|
//
|
|
// Either Initialize or QueryInterface failed.
|
|
//
|
|
delete pUserEnum;
|
|
pUserEnum = NULL;
|
|
}
|
|
}
|
|
catch(CAllocException& e)
|
|
{
|
|
hResult = E_OUTOFMEMORY;
|
|
}
|
|
|
|
return hResult;
|
|
}
|
|
|
|
|
|
|
|
DiskQuotaUserCollection::DiskQuotaUserCollection(
|
|
PDISKQUOTA_CONTROL pController,
|
|
DWORD fNameResolution
|
|
|
|
) : m_cRef(0),
|
|
m_pController(pController),
|
|
m_pEnum(NULL),
|
|
m_fNameResolution(fNameResolution)
|
|
{
|
|
if (NULL != m_pController)
|
|
{
|
|
m_pController->AddRef();
|
|
}
|
|
}
|
|
|
|
DiskQuotaUserCollection::~DiskQuotaUserCollection(
|
|
VOID
|
|
)
|
|
{
|
|
if (NULL != m_pEnum)
|
|
{
|
|
m_pEnum->Release();
|
|
}
|
|
if (NULL != m_pController)
|
|
{
|
|
m_pController->Release();
|
|
}
|
|
}
|
|
|
|
|
|
HRESULT
|
|
DiskQuotaUserCollection::Initialize(
|
|
VOID
|
|
)
|
|
{
|
|
HRESULT hr = S_FALSE; // Assume already initialized.
|
|
|
|
if (NULL == m_pEnum)
|
|
{
|
|
if (NULL == m_pController)
|
|
{
|
|
hr = E_UNEXPECTED;
|
|
}
|
|
else
|
|
{
|
|
hr = m_pController->CreateEnumUsers(NULL,
|
|
0,
|
|
m_fNameResolution,
|
|
&m_pEnum);
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: DiskQuotaUserCollection::QueryInterface
|
|
|
|
Description: Obtain pointer to IUnknown or IEnumDiskQuotaUserVARIANTs.
|
|
|
|
Arguments:
|
|
riid - Reference to requested interface ID.
|
|
|
|
ppvOut - Address of interface pointer variable to accept the
|
|
returned interface pointer.
|
|
|
|
Returns:
|
|
NO_ERROR - Success.
|
|
E_NOINTERFACE - Requested interface not supported.
|
|
E_INVALIDARG - ppvOut argument is NULL.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
08/22/97 Initial creation. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP
|
|
DiskQuotaUserCollection::QueryInterface(
|
|
REFIID riid,
|
|
LPVOID *ppvOut
|
|
)
|
|
{
|
|
HRESULT hResult = E_NOINTERFACE;
|
|
|
|
if (NULL == ppvOut)
|
|
return E_INVALIDARG;
|
|
|
|
*ppvOut = NULL;
|
|
|
|
if (IID_IUnknown == riid ||
|
|
IID_IEnumVARIANT == riid)
|
|
{
|
|
//
|
|
// Interface supported.
|
|
//
|
|
*ppvOut = this;
|
|
((LPUNKNOWN)*ppvOut)->AddRef();
|
|
hResult = NOERROR;
|
|
}
|
|
|
|
return hResult;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: DiskQuotaUserCollection::AddRef
|
|
|
|
Description: Increments object reference count.
|
|
|
|
Arguments: None.
|
|
|
|
Returns: New reference count value.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
08/22/97 Initial creation. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP_(ULONG)
|
|
DiskQuotaUserCollection::AddRef(
|
|
VOID
|
|
)
|
|
{
|
|
ULONG ulReturn = m_cRef + 1;
|
|
|
|
DBGPRINT((DM_COM, DL_HIGH, TEXT("DiskQuotaUserCollection::AddRef, 0x%08X %d -> %d"),
|
|
this, ulReturn - 1, ulReturn));
|
|
|
|
InterlockedIncrement(&m_cRef);
|
|
|
|
return ulReturn;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: DiskQuotaUserCollection::Release
|
|
|
|
Description: Decrements object reference count. If count drops to 0,
|
|
object is deleted.
|
|
|
|
Arguments: None.
|
|
|
|
Returns: New reference count value.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
08/22/97 Initial creation. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP_(ULONG)
|
|
DiskQuotaUserCollection::Release(
|
|
VOID
|
|
)
|
|
{
|
|
ULONG ulReturn = m_cRef - 1;
|
|
|
|
DBGPRINT((DM_COM, DL_HIGH, TEXT("DiskQuotaUserCollection::Release, 0x%08X %d -> %d"),
|
|
this, ulReturn + 1, ulReturn));
|
|
|
|
if (InterlockedDecrement(&m_cRef) == 0)
|
|
{
|
|
delete this;
|
|
ulReturn = 0;
|
|
}
|
|
return ulReturn;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
DiskQuotaUserCollection::Next(
|
|
DWORD cUsers,
|
|
VARIANT *rgvar,
|
|
DWORD *pcUsersFetched
|
|
)
|
|
{
|
|
HRESULT hr = E_UNEXPECTED;
|
|
try
|
|
{
|
|
if (NULL == pcUsersFetched && 1 < cUsers)
|
|
{
|
|
//
|
|
// If pcUsersFetched is NULL, cUsers must be 1.
|
|
//
|
|
hr = E_INVALIDARG;
|
|
}
|
|
else
|
|
{
|
|
DWORD cEnumerated = 0;
|
|
PDISKQUOTA_USER *prgUsers = new PDISKQUOTA_USER[cUsers];
|
|
if (NULL != prgUsers)
|
|
{
|
|
hr = m_pEnum->Next(cUsers, prgUsers, &cEnumerated);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
for (INT i = 0; i < (INT)cEnumerated; i++)
|
|
{
|
|
VariantInit(&rgvar[i]);
|
|
|
|
IDispatch *pIDisp = NULL;
|
|
hr = prgUsers[i]->QueryInterface(IID_IDispatch, (LPVOID *)&pIDisp);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
V_VT(&rgvar[i]) = VT_DISPATCH;
|
|
V_DISPATCH(&rgvar[i]) = pIDisp;
|
|
}
|
|
prgUsers[i]->Release();
|
|
}
|
|
}
|
|
delete[] prgUsers;
|
|
}
|
|
if (NULL != pcUsersFetched)
|
|
{
|
|
*pcUsersFetched = cEnumerated;
|
|
}
|
|
}
|
|
}
|
|
catch(CAllocException& e)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
DiskQuotaUserCollection::Skip(
|
|
DWORD cUsers
|
|
)
|
|
{
|
|
return m_pEnum->Skip(cUsers);
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DiskQuotaUserCollection::Reset(
|
|
void
|
|
)
|
|
{
|
|
return m_pEnum->Reset();
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
DiskQuotaUserCollection::Clone(
|
|
IEnumVARIANT **ppEnum
|
|
)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
try
|
|
{
|
|
DiskQuotaUserCollection *pEnum = new DiskQuotaUserCollection(m_pController,
|
|
m_fNameResolution);
|
|
if (NULL != pEnum)
|
|
{
|
|
hr = pEnum->Initialize();
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pEnum->QueryInterface(IID_IEnumVARIANT, (LPVOID *)ppEnum);
|
|
}
|
|
else
|
|
{
|
|
delete pEnum;
|
|
}
|
|
}
|
|
}
|
|
catch(CAllocException& me)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|