2042 lines
58 KiB
C++
2042 lines
58 KiB
C++
///////////////////////////////////////////////////////////////////////////////
|
|
/* File: user.cpp
|
|
|
|
Description: Contains member function definitions for class DiskQuotaUser.
|
|
The DiskQuotaUser object represents a user's record in a volume's
|
|
quota information file. The holder of a user object's IDiskQuotaUser
|
|
interface can query and modify information for that user as security
|
|
privileges permit. A user object is obtained through a UserEnumerator
|
|
object (IEnumDiskQuotaUsers) which is itself obtained through
|
|
IDiskQuotaControl::CreateEnumUsers().
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
05/22/96 Initial creation. BrianAu
|
|
08/20/96 Added m_dwID member to DiskQuotaUser. BrianAu
|
|
09/05/96 Added exception handling. BrianAu
|
|
03/18/98 Replaced "domain", "name" and "full name" with BrianAu
|
|
"container", "logon name" and "display name" to
|
|
better match the actual contents. This was in
|
|
reponse to making the quota UI DS-aware. The
|
|
"logon name" is now a unique key as it contains
|
|
both account name and domain-like information.
|
|
i.e. "REDMOND\brianau" or "brianau@microsoft.com".
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
#include "pch.h" // PCH
|
|
#pragma hdrstop
|
|
|
|
#include <comutil.h>
|
|
#include "user.h"
|
|
#include "resource.h" // For IDS_NO_LIMIT.
|
|
|
|
//
|
|
// Verify that build is UNICODE.
|
|
//
|
|
#if !defined(UNICODE)
|
|
# error This module must be compiled UNICODE.
|
|
#endif
|
|
|
|
|
|
//
|
|
// Only one of these for all users. (static member).
|
|
//
|
|
LONG DiskQuotaUser::m_cUsersAlive = 0; // Cnt of users alive now.
|
|
ULONG DiskQuotaUser::m_ulNextUniqueId = 0;
|
|
HANDLE DiskQuotaUser::m_hMutex = NULL;
|
|
DWORD DiskQuotaUser::m_dwMutexWaitTimeout = 5000; // 5 seconds.
|
|
CArray<CString> DiskQuotaUser::m_ContainerNameCache;
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: DiskQuotaUser::DiskQuotaUser
|
|
|
|
Description: Constructor.
|
|
|
|
Arguments:
|
|
pFSObject - Pointer to "file system" object. It is through this pointer
|
|
that the object accesses the ntioapi functions. Caller must call
|
|
AddRef() for this pointer prior to calling Initialize().
|
|
|
|
|
|
Returns: Nothing.
|
|
|
|
Exceptions: OutOfMemory.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
05/22/96 Initial creation. BrianAu
|
|
09/05/96 Added domain name string. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
DiskQuotaUser::DiskQuotaUser(
|
|
FSObject *pFSObject
|
|
) : m_cRef(0),
|
|
m_ulUniqueId(InterlockedIncrement((LONG *)&m_ulNextUniqueId)),
|
|
m_pSid(NULL),
|
|
m_pszLogonName(NULL),
|
|
m_pszDisplayName(NULL),
|
|
m_pFSObject(pFSObject),
|
|
m_bNeedCacheUpdate(TRUE), // Data cache, not domain name cache.
|
|
m_iContainerName(-1),
|
|
m_dwAccountStatus(DISKQUOTA_USER_ACCOUNT_UNRESOLVED)
|
|
{
|
|
DBGTRACE((DM_USER, DL_HIGH, TEXT("DiskQuotaUser::DiskQuotaUser")));
|
|
DBGPRINT((DM_USER, DL_HIGH, TEXT("\tthis = 0x%08X"), this));
|
|
DBGASSERT((NULL != m_pFSObject));
|
|
|
|
m_llQuotaUsed = 0;
|
|
m_llQuotaThreshold = 0;
|
|
m_llQuotaLimit = 0;
|
|
|
|
//
|
|
// Initialize the domain name cache and class-wide locking mutex.
|
|
// These members are static so we only do it once.
|
|
//
|
|
InterlockedIncrement(&m_cUsersAlive);
|
|
if (NULL == DiskQuotaUser::m_hMutex)
|
|
{
|
|
DiskQuotaUser::m_hMutex = CreateMutex(NULL, FALSE, NULL);
|
|
m_ContainerNameCache.SetSize(25);
|
|
m_ContainerNameCache.SetGrow(25);
|
|
}
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: DiskQuotaUser::~DiskQuotaUser
|
|
|
|
Description: Destructor
|
|
|
|
Arguments: None.
|
|
|
|
Returns: Nothing.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
05/22/96 Initial creation. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
DiskQuotaUser::~DiskQuotaUser(
|
|
VOID
|
|
)
|
|
{
|
|
DBGTRACE((DM_USER, DL_HIGH, TEXT("DiskQuotaUser::~DiskQuotaUser")));
|
|
DBGPRINT((DM_USER, DL_HIGH, TEXT("\tthis = 0x%08X"), this));
|
|
|
|
Destroy();
|
|
if (InterlockedDecrement(&m_cUsersAlive) == 0)
|
|
{
|
|
//
|
|
// If active user count is 0, destroy the domain name cache and
|
|
// class-wide mutex.
|
|
//
|
|
DestroyContainerNameCache();
|
|
|
|
if (NULL != DiskQuotaUser::m_hMutex)
|
|
{
|
|
CloseHandle(DiskQuotaUser::m_hMutex);
|
|
DiskQuotaUser::m_hMutex = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: DiskQuotaUser::QueryInterface
|
|
|
|
Description: Returns an interface pointer to the object's IUnknown or
|
|
IDiskQuotaUser interface. Only IID_IUnknown and
|
|
IID_IDiskQuotaUser are recognized. The object referenced by the
|
|
returned interface pointer is uninitialized. The recipient of the
|
|
pointer must call Initialize() before the object is usable.
|
|
|
|
Arguments:
|
|
riid - Reference to requested interface ID.
|
|
|
|
ppvOut - Address of interface pointer variable to accept interface ptr.
|
|
|
|
Returns:
|
|
NOERROR - Success.
|
|
E_NOINTERFACE - Requested interface not supported.
|
|
E_INVALIDARG - ppvOut argument was NULL.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
05/22/96 Initial creation. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP
|
|
DiskQuotaUser::QueryInterface(
|
|
REFIID riid,
|
|
LPVOID *ppvOut
|
|
)
|
|
{
|
|
DBGTRACE((DM_USER, DL_MID, TEXT("DiskQuotaUser::QueryInterface")));
|
|
DBGPRINTIID(DM_USER, DL_MID, riid);
|
|
|
|
HRESULT hResult = E_NOINTERFACE;
|
|
|
|
if (NULL == ppvOut)
|
|
return E_INVALIDARG;
|
|
|
|
try
|
|
{
|
|
*ppvOut = NULL;
|
|
|
|
if (IID_IUnknown == riid ||
|
|
IID_IDiskQuotaUser == riid)
|
|
{
|
|
*ppvOut = static_cast<IDiskQuotaUser *>(this);
|
|
}
|
|
else if (IID_IDispatch == riid ||
|
|
IID_DIDiskQuotaUser == riid)
|
|
{
|
|
//
|
|
// Create a disk quota user "dispatch" object to handle all of
|
|
// the automation duties. This object takes a pointer to the real
|
|
// user object so that it can call the real object to do the real
|
|
// work. The reason we use a special "dispatch" object is so that
|
|
// we can maintain identical names for dispatch and vtable methods
|
|
// that perform the same function. Otherwise, if the DiskQuotaUser
|
|
// object implements both IDiskQuotaUser and DIDiskQuotaUser methods,
|
|
// we could not have two methods named Invalidate (one for vtable
|
|
// and one for dispatch.
|
|
//
|
|
DiskQuotaUserDisp *pUserDisp = new DiskQuotaUserDisp(static_cast<PDISKQUOTA_USER>(this));
|
|
*ppvOut = static_cast<DIDiskQuotaUser *>(pUserDisp);
|
|
}
|
|
if (NULL != *ppvOut)
|
|
{
|
|
((LPUNKNOWN)*ppvOut)->AddRef();
|
|
hResult = NOERROR;
|
|
}
|
|
}
|
|
catch(CAllocException& e)
|
|
{
|
|
*ppvOut = NULL;
|
|
hResult = E_OUTOFMEMORY;
|
|
}
|
|
return hResult;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: DiskQuotaUser::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)
|
|
DiskQuotaUser::AddRef(
|
|
VOID
|
|
)
|
|
{
|
|
DBGTRACE((DM_USER, DL_LOW, TEXT("DiskQuotaUser::AddRef")));
|
|
DBGPRINT((DM_USER, DL_LOW, TEXT("\t0x%08X %d -> %d"),
|
|
this, m_cRef, m_cRef + 1));
|
|
|
|
ULONG ulReturn = m_cRef + 1;
|
|
InterlockedIncrement(&m_cRef);
|
|
return ulReturn;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: DiskQuotaUser::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)
|
|
DiskQuotaUser::Release(
|
|
VOID
|
|
)
|
|
{
|
|
DBGTRACE((DM_USER, DL_LOW, TEXT("DiskQuotaUser::Release")));
|
|
DBGPRINT((DM_USER, DL_LOW, TEXT("\t0x%08X %d -> %d"),
|
|
this, m_cRef, m_cRef - 1));
|
|
|
|
ULONG ulReturn = m_cRef - 1;
|
|
if (InterlockedDecrement(&m_cRef) == 0)
|
|
{
|
|
delete this;
|
|
ulReturn = 0;
|
|
}
|
|
return ulReturn;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: DiskQuotaUser::Initialize
|
|
|
|
Description: Initializes a new DiskQuotaUser object from a quota information
|
|
record read from a volume's quota information file.
|
|
|
|
Arguments:
|
|
pfqi [optional] - Pointer to a record of type FILE_QUOTA_INFORMATION. If
|
|
not NULL, the data from this record is used to initialize the new user
|
|
object.
|
|
|
|
Returns:
|
|
NOERROR - Success.
|
|
E_UNEXPECTED - SID buffer too small (shouldn't happen).
|
|
ERROR_INVALID_SID (hr) - SID in quota information is invalid.
|
|
ERROR_ACCESS_DENIED (hr) - Need READ access to quota device.
|
|
|
|
Exceptions: OutOfMemory.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
05/22/96 Initial creation. BrianAu
|
|
08/11/96 Added access control. BrianAu
|
|
09/05/96 Added exception handling. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
DiskQuotaUser::Initialize(
|
|
PFILE_QUOTA_INFORMATION pfqi
|
|
)
|
|
{
|
|
HRESULT hResult = NOERROR;
|
|
|
|
DBGASSERT((NULL != m_pFSObject));
|
|
|
|
//
|
|
// Need READ access to create a user object.
|
|
//
|
|
if (m_pFSObject->GrantedAccess(GENERIC_READ))
|
|
{
|
|
if (NULL != pfqi) // pfqi is optional.
|
|
{
|
|
if (0 < pfqi->SidLength && IsValidSid(&pfqi->Sid))
|
|
{
|
|
//
|
|
// Allocate space for SID structure.
|
|
//
|
|
m_pSid = (PSID) new BYTE[pfqi->SidLength];
|
|
|
|
//
|
|
// Copy SID structure to object.
|
|
//
|
|
if (CopySid(pfqi->SidLength, m_pSid, &pfqi->Sid))
|
|
{
|
|
//
|
|
// Initialize user's quota data values.
|
|
// If error copying SID, don't bother with these.
|
|
//
|
|
m_llQuotaUsed = pfqi->QuotaUsed.QuadPart;
|
|
m_llQuotaThreshold = pfqi->QuotaThreshold.QuadPart;
|
|
m_llQuotaLimit = pfqi->QuotaLimit.QuadPart;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// The only reason CopySid can fail is
|
|
// STATUS_BUFFER_TOO_SMALL. Since we allocated the buffer
|
|
// above, this should never fail.
|
|
//
|
|
DBGASSERT((FALSE));
|
|
hResult = E_UNEXPECTED; // Error copying SID.
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DBGERROR((TEXT("DiskQuotaUser::Initialize - Invalid SID or Bad Sid Length (%d)"), pfqi->SidLength));
|
|
hResult = HRESULT_FROM_WIN32(ERROR_INVALID_SID);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
hResult = HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
|
|
|
|
return hResult;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: DiskQuotaUser::Destroy
|
|
|
|
Description: Destroys a user object by deleting its SID buffer and releasing
|
|
its FSObject pointer.
|
|
|
|
Arguments: None.
|
|
|
|
Returns: Nothing.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
05/22/96 Initial creation. BrianAu
|
|
09/05/96 Added domain name string. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
VOID DiskQuotaUser::Destroy(
|
|
VOID
|
|
)
|
|
{
|
|
//
|
|
// Delete the SID buffer.
|
|
//
|
|
delete [] m_pSid;
|
|
m_pSid = NULL;
|
|
|
|
//
|
|
// Delete the logon name buffer.
|
|
//
|
|
delete[] m_pszLogonName;
|
|
m_pszLogonName = NULL;
|
|
|
|
//
|
|
// Delete the display name buffer.
|
|
//
|
|
delete[] m_pszDisplayName;
|
|
m_pszDisplayName = NULL;
|
|
|
|
if (NULL != m_pFSObject)
|
|
{
|
|
//
|
|
// Release hold on File System object.
|
|
//
|
|
m_pFSObject->Release();
|
|
m_pFSObject = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: DiskQuotaUser::DestroyContainerNameCache
|
|
|
|
Description: Destroys the container name cache. Should only be called
|
|
when there are not more active user objects. The container name cache
|
|
is a static member of DiskQuotaUser.
|
|
|
|
Arguments: None.
|
|
|
|
Returns: Nothing.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
09/06/96 Initial creation. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
VOID
|
|
DiskQuotaUser::DestroyContainerNameCache(
|
|
VOID
|
|
)
|
|
{
|
|
//
|
|
// Remove all container name strings from the cache. No need to lock
|
|
// the cache object before clearing it. It will handle the locking
|
|
// and unlocking.
|
|
//
|
|
m_ContainerNameCache.Clear();
|
|
}
|
|
|
|
|
|
//
|
|
// Return user object's unique ID.
|
|
//
|
|
STDMETHODIMP
|
|
DiskQuotaUser::GetID(
|
|
ULONG *pulID
|
|
)
|
|
{
|
|
*pulID = m_ulUniqueId;
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: DiskQuotaUser::GetAccountStatus
|
|
|
|
Description: Retrieves the account name resolution status for the
|
|
user object.
|
|
|
|
Arguments:
|
|
pdwAccountStatus - Address of variable to recieve status. The following
|
|
values (see dskquota.h) can be returned in this variable:
|
|
|
|
DISKQUOTA_USER_ACCOUNT_RESOLVED
|
|
DISKQUOTA_USER_ACCOUNT_UNAVAILABLE
|
|
DISKQUOTA_USER_ACCOUNT_DELETED
|
|
DISKQUOTA_USER_ACCOUNT_INVALID
|
|
DISKQUOTA_USER_ACCOUNT_UNKNOWN
|
|
DISKQUOTA_USER_ACCOUNT_UNRESOLVED
|
|
|
|
Returns:
|
|
NOERROR - Success.
|
|
E_INVALIDARG - pdwAccountStatus arg is NULL.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
06/11/96 Initial creation. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP
|
|
DiskQuotaUser::GetAccountStatus(
|
|
LPDWORD pdwAccountStatus
|
|
)
|
|
{
|
|
if (NULL == pdwAccountStatus)
|
|
return E_INVALIDARG;
|
|
|
|
*pdwAccountStatus = m_dwAccountStatus;
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: DiskQuotaUser::SetName
|
|
|
|
Description: Sets the account names of the user object.
|
|
It is intended that the SidNameResolver object will call this member
|
|
when it has resolved a user's SID into an account name. This function
|
|
is not included in IDiskQuotaUser. Therefore, it is not for public
|
|
consumption.
|
|
|
|
Arguments:
|
|
pszContainer - Address of buffer containing container name string.
|
|
|
|
pszLogonName - Address of buffer containing user's logon name string.
|
|
|
|
pszDisplayName - Address of buffer containing user's display name string.
|
|
|
|
Returns:
|
|
NOERROR - Success.
|
|
E_INVALIDARG - pszName or pszDomain arg is NULL.
|
|
E_OUTOFMEMORY - Insufficient memory.
|
|
ERROR_LOCK_FAILED (hr) - Couldn't lock user object.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
06/11/96 Initial creation. BrianAu
|
|
09/05/96 Added domain name string. BrianAu
|
|
09/22/96 Added full name string. BrianAu
|
|
12/10/96 Added class-scope user lock. BrianAu
|
|
05/18/97 Removed access token. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP
|
|
DiskQuotaUser::SetName(
|
|
LPCWSTR pszContainer,
|
|
LPCWSTR pszLogonName,
|
|
LPCWSTR pszDisplayName
|
|
)
|
|
{
|
|
HRESULT hResult = NOERROR;
|
|
|
|
if (NULL == pszContainer || NULL == pszLogonName || NULL == pszDisplayName)
|
|
return E_INVALIDARG;
|
|
|
|
if (!DiskQuotaUser::Lock())
|
|
{
|
|
hResult = HRESULT_FROM_WIN32(ERROR_LOCK_FAILED);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Delete existing name buffer.
|
|
//
|
|
delete[] m_pszLogonName;
|
|
m_pszLogonName = NULL;
|
|
delete[] m_pszDisplayName;
|
|
m_pszDisplayName = NULL;
|
|
|
|
try
|
|
{
|
|
//
|
|
// Save name and full name in user object.
|
|
// Cache container string in container name cache and
|
|
// save cache index in user object.
|
|
//
|
|
INT index = -1;
|
|
m_pszLogonName = StringDup(pszLogonName);
|
|
m_pszDisplayName = StringDup(pszDisplayName);
|
|
CacheContainerName(pszContainer, &m_iContainerName);
|
|
}
|
|
catch(CAllocException& e)
|
|
{
|
|
hResult = E_OUTOFMEMORY;
|
|
}
|
|
DiskQuotaUser::ReleaseLock();
|
|
}
|
|
|
|
return hResult;
|
|
}
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: DiskQuotaUser::GetName
|
|
|
|
Description: Retrieves the domain and account names from the user object.
|
|
It is intended that the client of the user object will register
|
|
a callback (event sink) with a DiskQuotaControl object. When the
|
|
resolver has resolved the SID to an account name, the resolver will
|
|
set the user object's name string and the client will be notified.
|
|
The client then calls this method to get the user's name.
|
|
|
|
Arguments:
|
|
pszContainerBuffer - Address of destination buffer for container name string.
|
|
|
|
cchContainerBuffer - Size of container destination buffer in characters.
|
|
|
|
pszLogonNameBuffer - Address of destination buffer for logon name string.
|
|
|
|
cchLogonNameBuffer - Size of logon name destination buffer in characters.
|
|
|
|
pszDisplayNameBuffer - Address of destination buffer for display name string.
|
|
|
|
cchDisplayNameBuffer - Size of display name destination buffer in characters.
|
|
|
|
Returns:
|
|
NOERROR - Success.
|
|
ERROR_LOCK_FAILED (hr) - Failed to lock user object.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
06/11/96 Initial creation. BrianAu
|
|
09/05/96 Added domain name string. BrianAu
|
|
09/22/96 Added full name string. BrianAu
|
|
12/10/96 Added class-scope user lock. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP
|
|
DiskQuotaUser::GetName(
|
|
LPWSTR pszContainerBuffer,
|
|
DWORD cchContainerBuffer,
|
|
LPWSTR pszLogonNameBuffer,
|
|
DWORD cchLogonNameBuffer,
|
|
LPWSTR pszDisplayNameBuffer,
|
|
DWORD cchDisplayNameBuffer
|
|
)
|
|
{
|
|
HRESULT hResult = NOERROR;
|
|
if (!DiskQuotaUser::Lock())
|
|
{
|
|
hResult = HRESULT_FROM_WIN32(ERROR_LOCK_FAILED);
|
|
}
|
|
else
|
|
{
|
|
if (NULL != pszContainerBuffer)
|
|
{
|
|
if (-1 != m_iContainerName)
|
|
{
|
|
GetCachedContainerName(m_iContainerName,
|
|
pszContainerBuffer,
|
|
cchContainerBuffer);
|
|
}
|
|
else
|
|
lstrcpyn(pszContainerBuffer, TEXT(""), cchContainerBuffer);
|
|
}
|
|
|
|
if (NULL != pszLogonNameBuffer)
|
|
{
|
|
lstrcpyn(pszLogonNameBuffer,
|
|
(NULL != m_pszLogonName) ? m_pszLogonName : TEXT(""),
|
|
cchLogonNameBuffer);
|
|
}
|
|
|
|
if (NULL != pszDisplayNameBuffer)
|
|
{
|
|
lstrcpyn(pszDisplayNameBuffer,
|
|
(NULL != m_pszDisplayName) ? m_pszDisplayName : TEXT(""),
|
|
cchDisplayNameBuffer);
|
|
}
|
|
DiskQuotaUser::ReleaseLock();
|
|
}
|
|
|
|
return hResult;
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: DiskQuotaUser::GetSidLength
|
|
|
|
Description: Retrieves the length of the user's SID in bytes.
|
|
|
|
Arguments:
|
|
pcbSid - Address of DWORD to accept SID length value.
|
|
|
|
Returns:
|
|
NOERROR - Success.
|
|
E_INVALIDARG - pcbSid argument is NULL.
|
|
ERROR_INVALID_SID (hr) - Invalid SID.
|
|
ERROR_LOCK_FAILED (hr) - Couldn't lock user object.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
05/22/96 Initial creation. BrianAu
|
|
12/10/96 Added class-scope user lock. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP
|
|
DiskQuotaUser::GetSidLength(
|
|
LPDWORD pcbSid
|
|
)
|
|
{
|
|
HRESULT hResult = NOERROR;
|
|
|
|
if (NULL == pcbSid)
|
|
return E_INVALIDARG;
|
|
|
|
if (!DiskQuotaUser::Lock())
|
|
{
|
|
hResult = HRESULT_FROM_WIN32(ERROR_LOCK_FAILED);
|
|
}
|
|
else
|
|
{
|
|
if (NULL != m_pSid && IsValidSid(m_pSid))
|
|
{
|
|
*pcbSid = GetLengthSid(m_pSid);
|
|
}
|
|
else
|
|
hResult = HRESULT_FROM_WIN32(ERROR_INVALID_SID);
|
|
|
|
DiskQuotaUser::ReleaseLock();
|
|
}
|
|
|
|
return hResult;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: DiskQuotaUser::GetSid
|
|
|
|
Description: Retrieves the user's SID to a caller-provided buffer.
|
|
The caller should call GetSidLength() to obtain the required buffer
|
|
size before calling GetSid().
|
|
|
|
Arguments:
|
|
pSid - Address of destination buffer for SID. This argument type must
|
|
be PBYTE to work with the MIDL compiler. Since PSID is really just
|
|
LPVOID and since MIDL doesn't like pointers to void, we have to
|
|
use something other than PSID.
|
|
|
|
cbSidBuf - Size of destination buffer in bytes.
|
|
|
|
Returns:
|
|
NOERROR - Success.
|
|
E_INVALIDARG - pSID is NULL.
|
|
ERROR_INVALID_SID (hr) - User's SID is invalid.
|
|
ERROR_INSUFFICIENT_BUFFER (hr) - Insufficient dest buffer size.
|
|
ERROR_LOCK_FAILED (hr) - Couldn't lock user object.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
05/22/96 Initial creation. BrianAu
|
|
12/10/96 Added class-scope user lock. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP
|
|
DiskQuotaUser::GetSid(
|
|
PBYTE pSid,
|
|
DWORD cbSidBuf
|
|
)
|
|
{
|
|
HRESULT hResult = NOERROR;
|
|
|
|
if (NULL == pSid)
|
|
return E_INVALIDARG;
|
|
|
|
if (!DiskQuotaUser::Lock())
|
|
{
|
|
hResult = HRESULT_FROM_WIN32(ERROR_LOCK_FAILED);
|
|
}
|
|
else
|
|
{
|
|
if (NULL != m_pSid && IsValidSid(m_pSid))
|
|
{
|
|
if (!CopySid(cbSidBuf, (PSID)pSid, m_pSid))
|
|
{
|
|
//
|
|
// The only reason CopySid can fail is STATUS_BUFFER_TOO_SMALL.
|
|
// Force status code to INSUFFICIENT_BUFFER.
|
|
//
|
|
DBGERROR((TEXT("ERROR in DiskQuotaUser::GetSid. CopySid() failed. Result = 0x%08X."),
|
|
GetLastError()));
|
|
hResult = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DBGERROR((TEXT("ERROR in DiskQuotaUser::GetSid. Invalid SID.")));
|
|
hResult = HRESULT_FROM_WIN32(ERROR_INVALID_SID);
|
|
}
|
|
DiskQuotaUser::ReleaseLock();
|
|
}
|
|
|
|
return hResult;
|
|
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: DiskQuotaUser::RefreshCachedInfo
|
|
|
|
Description: Refreshes a user object's cached quota information from the
|
|
volume's quota information file.
|
|
|
|
Arguments: None.
|
|
|
|
Returns:
|
|
NOERROR - Success.
|
|
ERROR_ACCESS_DENIED (hr) - No READ access to quota device.
|
|
E_FAIL - Unexpected NTIOAPI error.
|
|
|
|
This function can propagate errors from the NTIOAPI system. A few
|
|
known ones are mapped to HResults in fsobject.cpp (see HResultFromNtStatus).
|
|
All others are mapped to E_FAIL.
|
|
|
|
Exceptions: OutOfMemory.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
06/05/96 Initial creation. BrianAu
|
|
09/05/96 Added exception handling. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
DiskQuotaUser::RefreshCachedInfo(
|
|
VOID
|
|
)
|
|
{
|
|
HRESULT hResult = NOERROR;
|
|
DWORD cbBuffer = FILE_QUOTA_INFORMATION_MAX_LEN;
|
|
PSIDLIST pSidList = NULL;
|
|
DWORD cbSidList = 0;
|
|
PSID pSids[] = { m_pSid, NULL };
|
|
PBYTE pbBuffer = NULL;
|
|
|
|
try
|
|
{
|
|
pbBuffer = new BYTE[cbBuffer];
|
|
|
|
//
|
|
// This can throw OutOfMemory.
|
|
//
|
|
hResult = CreateSidList(pSids, 0, &pSidList, &cbSidList);
|
|
if (SUCCEEDED(hResult))
|
|
{
|
|
hResult = m_pFSObject->QueryUserQuotaInformation(
|
|
pbBuffer, // Buffer to receive data.
|
|
cbBuffer, // Buffer size in bytes.
|
|
TRUE, // Single entry requested.
|
|
pSidList, // Sid.
|
|
cbSidList, // Length of Sid.
|
|
NULL, // Starting Sid
|
|
TRUE); // Start search at first user.
|
|
|
|
if (SUCCEEDED(hResult) || ERROR_NO_MORE_ITEMS == HRESULT_CODE(hResult))
|
|
{
|
|
PFILE_QUOTA_INFORMATION pfqi = (PFILE_QUOTA_INFORMATION)pbBuffer;
|
|
|
|
m_llQuotaUsed = pfqi->QuotaUsed.QuadPart;
|
|
m_llQuotaThreshold = pfqi->QuotaThreshold.QuadPart;
|
|
m_llQuotaLimit = pfqi->QuotaLimit.QuadPart;
|
|
m_bNeedCacheUpdate = FALSE;
|
|
|
|
//
|
|
// Don't return ERROR_NO_MORE_ITEMS to caller.
|
|
// They won't care.
|
|
//
|
|
hResult = NOERROR;
|
|
}
|
|
delete[] pSidList;
|
|
}
|
|
delete[] pbBuffer;
|
|
}
|
|
catch(CAllocException& e)
|
|
{
|
|
hResult = E_OUTOFMEMORY;
|
|
delete[] pbBuffer;
|
|
delete[] pSidList;
|
|
}
|
|
return hResult;
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: DiskQuotaUser::WriteCachedInfo
|
|
|
|
Description: Writes quota information cached in a user object to the
|
|
volume's quota information file.
|
|
|
|
Arguments: None.
|
|
|
|
Returns:
|
|
NOERROR - Success.
|
|
ERROR_ACCESS_DENIED (hr) - No WRITE access to quota device.
|
|
E_FAIL - Some other NTIOAPI error.
|
|
E_UNEXPECTED - CopySid failed.
|
|
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
07/31/96 Initial creation. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
DiskQuotaUser::WriteCachedInfo(
|
|
VOID
|
|
)
|
|
{
|
|
HRESULT hResult = NOERROR;
|
|
BYTE Buffer[FILE_QUOTA_INFORMATION_MAX_LEN];
|
|
|
|
PFILE_QUOTA_INFORMATION pfqi = (PFILE_QUOTA_INFORMATION)Buffer;
|
|
|
|
pfqi->NextEntryOffset = 0;
|
|
pfqi->SidLength = GetLengthSid(m_pSid);
|
|
pfqi->QuotaUsed.QuadPart = m_llQuotaUsed;
|
|
pfqi->QuotaLimit.QuadPart = m_llQuotaLimit;
|
|
pfqi->QuotaThreshold.QuadPart = m_llQuotaThreshold;
|
|
|
|
if (CopySid(pfqi->SidLength, &(pfqi->Sid), m_pSid))
|
|
hResult = m_pFSObject->SetUserQuotaInformation(pfqi, sizeof(Buffer));
|
|
else
|
|
hResult = E_UNEXPECTED;
|
|
|
|
if (FAILED(hResult))
|
|
{
|
|
//
|
|
// Something failed.
|
|
// Invalidate cached information so next request reads from disk.
|
|
//
|
|
Invalidate();
|
|
}
|
|
|
|
|
|
return hResult;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: DiskQuotaUser::GetQuotaInformation
|
|
|
|
Description: Retrieves a user's quota limit, threshold and used quota
|
|
values in a single method. Since the user interface is marshaled
|
|
across thread boundaries, this can be a big performance improvement
|
|
if you want all three values.
|
|
|
|
Arguments:
|
|
pbInfo - Address of destination buffer. Should be sized for structure
|
|
DISKQUOTA_USER_INFORMATION.
|
|
|
|
cbInfo - Number of bytes in destination buffer. Should be
|
|
sizeof(DISKQUOTA_USER_INFORMATION).
|
|
|
|
Returns:
|
|
NOERROR - Success.
|
|
E_INVALIDARG - pbInfo argument is NULL.
|
|
E_OUTOFMEMORY - Insufficient memory.
|
|
ERROR_INSUFFICIENT_BUFFER (hr) - Destination buffer is too small.
|
|
ERROR_LOCK_FAILED (hr) - Couldn't lock user object.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
07/31/96 Initial creation. BrianAu
|
|
12/10/96 Added class-scope user lock. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP
|
|
DiskQuotaUser::GetQuotaInformation(
|
|
LPVOID pbInfo,
|
|
DWORD cbInfo
|
|
)
|
|
{
|
|
HRESULT hResult = NOERROR;
|
|
|
|
if (NULL == pbInfo)
|
|
return E_INVALIDARG;
|
|
|
|
try
|
|
{
|
|
if (cbInfo < sizeof(DISKQUOTA_USER_INFORMATION))
|
|
{
|
|
hResult = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
|
|
}
|
|
else
|
|
{
|
|
if (!DiskQuotaUser::Lock())
|
|
{
|
|
hResult = HRESULT_FROM_WIN32(ERROR_LOCK_FAILED);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Refresh cached info from disk if needed.
|
|
// Can throw OutOfMemory.
|
|
//
|
|
if (m_bNeedCacheUpdate)
|
|
hResult = RefreshCachedInfo();
|
|
|
|
if (SUCCEEDED(hResult))
|
|
{
|
|
PDISKQUOTA_USER_INFORMATION pui = (PDISKQUOTA_USER_INFORMATION)pbInfo;
|
|
|
|
pui->QuotaUsed = m_llQuotaUsed;
|
|
pui->QuotaThreshold = m_llQuotaThreshold;
|
|
pui->QuotaLimit = m_llQuotaLimit;
|
|
}
|
|
DiskQuotaUser::ReleaseLock();
|
|
}
|
|
}
|
|
}
|
|
catch(CAllocException& e)
|
|
{
|
|
hResult = E_OUTOFMEMORY;
|
|
}
|
|
return hResult;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
DiskQuotaUser::GetQuotaUsedText(
|
|
LPWSTR pszText,
|
|
DWORD cchText
|
|
)
|
|
{
|
|
if (NULL == pszText)
|
|
return E_INVALIDARG;
|
|
|
|
LONGLONG llValue;
|
|
HRESULT hr = GetQuotaUsed(&llValue);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (NOLIMIT == llValue)
|
|
{
|
|
LoadString(g_hInstDll, IDS_NO_LIMIT, pszText, cchText);
|
|
}
|
|
else
|
|
{
|
|
XBytes::FormatByteCountForDisplay(llValue, pszText, cchText);
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DiskQuotaUser::GetQuotaThresholdText(
|
|
LPWSTR pszText,
|
|
DWORD cchText
|
|
)
|
|
{
|
|
if (NULL == pszText)
|
|
return E_INVALIDARG;
|
|
|
|
LONGLONG llValue;
|
|
HRESULT hr = GetQuotaThreshold(&llValue);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (NOLIMIT == llValue)
|
|
{
|
|
LoadString(g_hInstDll, IDS_NO_LIMIT, pszText, cchText);
|
|
}
|
|
else
|
|
{
|
|
XBytes::FormatByteCountForDisplay(llValue, pszText, cchText);
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
DiskQuotaUser::GetQuotaLimitText(
|
|
LPWSTR pszText,
|
|
DWORD cchText
|
|
)
|
|
{
|
|
if (NULL == pszText)
|
|
return E_INVALIDARG;
|
|
|
|
LONGLONG llValue;
|
|
HRESULT hr = GetQuotaLimit(&llValue);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (NOLIMIT == llValue)
|
|
{
|
|
LoadString(g_hInstDll, IDS_NO_LIMIT, pszText, cchText);
|
|
}
|
|
else
|
|
{
|
|
XBytes::FormatByteCountForDisplay(llValue, pszText, cchText);
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
DiskQuotaUser::SetQuotaThreshold(
|
|
LONGLONG llThreshold,
|
|
BOOL bWriteThrough
|
|
)
|
|
{
|
|
if (MARK4DEL > llThreshold)
|
|
return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
|
|
|
|
return SetLargeIntegerQuotaItem(&m_llQuotaThreshold,
|
|
llThreshold,
|
|
bWriteThrough);
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
DiskQuotaUser::SetQuotaLimit(
|
|
LONGLONG llLimit,
|
|
BOOL bWriteThrough
|
|
)
|
|
{
|
|
if (MARK4DEL > llLimit)
|
|
return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
|
|
|
|
return SetLargeIntegerQuotaItem(&m_llQuotaLimit,
|
|
llLimit,
|
|
bWriteThrough);
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: DiskQuotaUser::GetLargeIntegerQuotaItem
|
|
|
|
Description: Retrieves a single quota information item (used, limit,
|
|
threshold) for the user. If the cached data is invalid, fresh data is
|
|
read in from disk.
|
|
|
|
Arguments:
|
|
pllItem - Address of cached member item.
|
|
|
|
pllValueOut - Address of LONGLONG to receive item's value.
|
|
|
|
Returns:
|
|
NOERROR - Success.
|
|
E_INVALIDARG - Either pdwLowPart or pdwHighPart arg was NULL.
|
|
E_OUTOFMEMORY - Insufficient memory.
|
|
E_UNEXPECTED - Unexpected exception.
|
|
ERROR_LOCK_FAILED (hr) - Couldn't lock user object.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
06/05/96 Initial creation. BrianAu
|
|
12/10/96 Added class-scope user lock. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
DiskQuotaUser::GetLargeIntegerQuotaItem(
|
|
PLONGLONG pllItem,
|
|
PLONGLONG pllValueOut
|
|
)
|
|
{
|
|
HRESULT hResult = NOERROR;
|
|
|
|
DBGASSERT((NULL != pllItem));
|
|
|
|
if (NULL == pllItem || NULL == pllValueOut)
|
|
return E_INVALIDARG;
|
|
|
|
if (!DiskQuotaUser::Lock())
|
|
{
|
|
hResult = HRESULT_FROM_WIN32(ERROR_LOCK_FAILED);
|
|
}
|
|
else
|
|
{
|
|
if (m_bNeedCacheUpdate)
|
|
try
|
|
{
|
|
hResult = RefreshCachedInfo();
|
|
}
|
|
catch(CAllocException& e)
|
|
{
|
|
hResult = E_OUTOFMEMORY;
|
|
}
|
|
if (SUCCEEDED(hResult))
|
|
{
|
|
*pllValueOut = *pllItem;
|
|
}
|
|
DiskQuotaUser::ReleaseLock();
|
|
}
|
|
|
|
return hResult;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: DiskQuotaUser::SetLargeIntegerQuotaItem
|
|
|
|
Description: Sets the quota information for a given quota item (limit or
|
|
threshold). If the bWriteThrough argument is TRUE, the information is
|
|
also written through to the volume's quota file. Otherwise, it is
|
|
just cached in the user object.
|
|
|
|
Arguments:
|
|
pllItem - Address of cached member item.
|
|
|
|
llValue - LONGLONG value to assign to member item.
|
|
|
|
bWriteThrough - TRUE = Write data through to disk.
|
|
FALSE = Only cache data in user object.
|
|
|
|
Returns:
|
|
NOERROR - Success.
|
|
ERROR_ACCESS_DENIED (hr) - No WRITE access to quota device.
|
|
ERROR_LOCK_FAILED (hr) - Couldn't lock user object.
|
|
E_FAIL - Some other NTIOAPI error.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
08/06/96 Initial creation. BrianAu
|
|
12/10/96 Added class-scope user lock. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
DiskQuotaUser::SetLargeIntegerQuotaItem(
|
|
PLONGLONG pllItem,
|
|
LONGLONG llValue,
|
|
BOOL bWriteThrough)
|
|
{
|
|
DBGASSERT((NULL != pllItem));
|
|
HRESULT hResult = NOERROR;
|
|
|
|
if (!DiskQuotaUser::Lock())
|
|
{
|
|
hResult = HRESULT_FROM_WIN32(ERROR_LOCK_FAILED);
|
|
}
|
|
else
|
|
{
|
|
*pllItem = llValue;
|
|
if (bWriteThrough)
|
|
hResult = WriteCachedInfo();
|
|
|
|
DiskQuotaUser::ReleaseLock();
|
|
}
|
|
|
|
return hResult;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: DiskQuotaUser::CacheContainerName
|
|
|
|
Description: Class DiskQuotaUser maintains a static member that is
|
|
a cache of account container names. It is likely that there will be
|
|
few distinct container names in use on a volume. Therefore, there's
|
|
no need to store a container name for each user object. We cache the
|
|
names and store only an index into the cache in each user object.
|
|
|
|
This method adds a name to the cache and returns the index of the
|
|
name in the cache. If the name already exists in the cache,
|
|
it is not added.
|
|
|
|
Arguments:
|
|
pszContainer - Address of container name string to add to cache.
|
|
|
|
pCacheIndex [optional] - Address of integer variable to receive the
|
|
cache index of the container name string. May be NULL.
|
|
|
|
Returns:
|
|
S_OK - Success.
|
|
S_FALSE - Name already in cache.
|
|
E_FAIL - No cache object.
|
|
|
|
Exceptions: OutOfMemory.
|
|
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
09/05/09 Initial creation. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
DiskQuotaUser::CacheContainerName(
|
|
LPCTSTR pszContainer,
|
|
INT *pCacheIndex
|
|
)
|
|
{
|
|
DBGASSERT((NULL != pszContainer));
|
|
|
|
HRESULT hResult = S_OK;
|
|
INT iCacheIndex = -1;
|
|
UINT cItems = 0;
|
|
|
|
m_ContainerNameCache.Lock();
|
|
|
|
cItems = m_ContainerNameCache.Count();
|
|
|
|
for (UINT i = 0; i < cItems; i++)
|
|
{
|
|
//
|
|
// See if the name is already in the cache.
|
|
//
|
|
if (0 == m_ContainerNameCache[i].Compare(pszContainer))
|
|
{
|
|
iCacheIndex = i;
|
|
hResult = S_FALSE; // Already cached.
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (S_OK == hResult)
|
|
{
|
|
//
|
|
// Not in the cache. Add it.
|
|
//
|
|
try
|
|
{
|
|
m_ContainerNameCache.Append(CString(pszContainer));
|
|
iCacheIndex = m_ContainerNameCache.UpperBound();
|
|
}
|
|
catch(CAllocException& e)
|
|
{
|
|
hResult = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
m_ContainerNameCache.ReleaseLock();
|
|
|
|
if (NULL != pCacheIndex)
|
|
*pCacheIndex = iCacheIndex;
|
|
|
|
return hResult;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: DiskQuotaUser::GetCachedContainerName
|
|
|
|
Description: Retrieves an account container name string from the
|
|
container name cache.
|
|
|
|
Arguments:
|
|
iCacheIndex - User's index in domain name cache.
|
|
|
|
pszContainer - Destination buffer to receive container name string.
|
|
|
|
cchContainer - Number of characters in destination buffer.
|
|
|
|
Returns:
|
|
NOERROR - Success.
|
|
E_UNEXPECTED - No name at index iCacheIndex. Returns "" as name.
|
|
E_FAIL - No domain name cache object.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
09/05/96 Initial creation. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
DiskQuotaUser::GetCachedContainerName(
|
|
INT iCacheIndex,
|
|
LPTSTR pszContainer,
|
|
UINT cchContainer
|
|
)
|
|
{
|
|
DBGASSERT((NULL != pszContainer));
|
|
DBGASSERT((-1 != iCacheIndex));
|
|
|
|
HRESULT hResult = NOERROR;
|
|
|
|
m_ContainerNameCache.Lock();
|
|
|
|
DBGASSERT((iCacheIndex < m_ContainerNameCache.Count()));
|
|
|
|
lstrcpyn(pszContainer, m_ContainerNameCache[iCacheIndex], cchContainer);
|
|
|
|
m_ContainerNameCache.ReleaseLock();
|
|
|
|
return hResult;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: DiskQuotaUser::Lock
|
|
|
|
Description: Call this to obtain an exclusive lock to the user object.
|
|
In actuality, there is only one lock for all user objects so you're
|
|
really getting an exclusive lock to all users. Since there can be
|
|
a high number of users, it was decided to use a single class-wide
|
|
lock instead of a unique lock for each user object.
|
|
|
|
Arguments: None.
|
|
|
|
Returns:
|
|
TRUE = Obtained exclusive lock.
|
|
FALSE = Couldn't get a lock. Either mutex hasn't been created or
|
|
the mutex wait timeout expired, or the wait operation failed.
|
|
Either way, we couldn't get the lock.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
12/10/96 Initial creation. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
BOOL
|
|
DiskQuotaUser::Lock(
|
|
VOID
|
|
)
|
|
{
|
|
BOOL bResult = FALSE;
|
|
|
|
if (NULL != DiskQuotaUser::m_hMutex)
|
|
{
|
|
DWORD dwWaitResult = WaitForSingleObject(DiskQuotaUser::m_hMutex,
|
|
DiskQuotaUser::m_dwMutexWaitTimeout);
|
|
bResult = (WAIT_OBJECT_0 == dwWaitResult);
|
|
}
|
|
return bResult;
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: DiskQuotaUser::ReleaseLock
|
|
|
|
Description: Call this to release a lock obtained with DiskQuotaUser::Lock.
|
|
|
|
Arguments: None.
|
|
|
|
Returns: Nothing.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
12/10/96 Initial creation. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
VOID
|
|
DiskQuotaUser::ReleaseLock(
|
|
VOID
|
|
)
|
|
{
|
|
if (NULL != DiskQuotaUser::m_hMutex)
|
|
{
|
|
ReleaseMutex(DiskQuotaUser::m_hMutex);
|
|
}
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: DiskQuotaUser::SetAccountStatus
|
|
|
|
Description: Stores the status of the user's account in the user object.
|
|
User accounts may be "unresolved", "unavailable", "resolved",
|
|
"deleted", "invalid" or "unknown".
|
|
These states correspond to the values obtained
|
|
through LookupAccountSid.
|
|
|
|
Arguments:
|
|
dwStatus - DISKQUOTA_USER_ACCOUNT_UNRESOLVED
|
|
DISKQUOTA_USER_ACCOUNT_UNAVAILABLE
|
|
DISKQUOTA_USER_ACCOUNT_RESOLVED
|
|
DISKQUOTA_USER_ACCOUNT_DELETED
|
|
DISKQUOTA_USER_ACCOUNT_UNKNOWN
|
|
DISKQUOTA_USER_ACCOUNT_INVALID
|
|
|
|
Returns: Nothing.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
05/18/97 Initial creation. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
VOID
|
|
DiskQuotaUser::SetAccountStatus(
|
|
DWORD dwStatus
|
|
)
|
|
{
|
|
DBGASSERT((DISKQUOTA_USER_ACCOUNT_UNRESOLVED == dwStatus ||
|
|
DISKQUOTA_USER_ACCOUNT_UNAVAILABLE == dwStatus ||
|
|
DISKQUOTA_USER_ACCOUNT_RESOLVED == dwStatus ||
|
|
DISKQUOTA_USER_ACCOUNT_DELETED == dwStatus ||
|
|
DISKQUOTA_USER_ACCOUNT_INVALID == dwStatus ||
|
|
DISKQUOTA_USER_ACCOUNT_UNKNOWN == dwStatus));
|
|
|
|
m_dwAccountStatus = dwStatus;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// The following functions implement the DiskQuotaUser "dispatch" object that
|
|
// is created to handle OLE automation duties for the DiskQuotaUser object.
|
|
// The functions are all fairly basic and require little explanation.
|
|
// Therefore, I'll spare you the function headers. In most cases,
|
|
// the property and method functions call directly through to their
|
|
// corresponding functions in class DiskQuotaUser.
|
|
//
|
|
DiskQuotaUserDisp::DiskQuotaUserDisp(
|
|
PDISKQUOTA_USER pUser
|
|
) : m_cRef(0),
|
|
m_pUser(pUser)
|
|
{
|
|
DBGTRACE((DM_USER, DL_HIGH, TEXT("DiskQuotaUserDisp::DiskQuotaUserDisp")));
|
|
DBGPRINT((DM_USER, DL_HIGH, TEXT("\tthis = 0x%08X"), this));
|
|
|
|
if (NULL != m_pUser)
|
|
{
|
|
m_pUser->AddRef();
|
|
}
|
|
m_Dispatch.Initialize(static_cast<IDispatch *>(this),
|
|
LIBID_DiskQuotaTypeLibrary,
|
|
IID_DIDiskQuotaUser,
|
|
L"DSKQUOTA.DLL");
|
|
}
|
|
|
|
DiskQuotaUserDisp::~DiskQuotaUserDisp(
|
|
VOID
|
|
)
|
|
{
|
|
DBGTRACE((DM_USER, DL_HIGH, TEXT("DiskQuotaUserDisp::~DiskQuotaUserDisp")));
|
|
DBGPRINT((DM_USER, DL_HIGH, TEXT("\tthis = 0x%08X"), this));
|
|
|
|
if (NULL != m_pUser)
|
|
{
|
|
m_pUser->Release();
|
|
}
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
DiskQuotaUserDisp::QueryInterface(
|
|
REFIID riid,
|
|
LPVOID *ppvOut
|
|
)
|
|
{
|
|
DBGTRACE((DM_USER, DL_MID, TEXT("DiskQuotaUserDisp::QueryInterface")));
|
|
DBGPRINTIID(DM_USER, DL_MID, riid);
|
|
|
|
HRESULT hResult = E_NOINTERFACE;
|
|
|
|
if (NULL == ppvOut)
|
|
return E_INVALIDARG;
|
|
|
|
*ppvOut = NULL;
|
|
|
|
if (IID_IUnknown == riid)
|
|
{
|
|
*ppvOut = this;
|
|
}
|
|
else if (IID_IDispatch == riid)
|
|
{
|
|
*ppvOut = static_cast<IDispatch *>(this);
|
|
}
|
|
else if (IID_DIDiskQuotaUser == riid)
|
|
{
|
|
*ppvOut = static_cast<DIDiskQuotaUser *>(this);
|
|
}
|
|
else if (IID_IDiskQuotaUser == riid)
|
|
{
|
|
//
|
|
// Return the quota user's vtable interface.
|
|
// This allows code to "typecast" (COM-style) between
|
|
// the dispatch interface and vtable interface.
|
|
//
|
|
return m_pUser->QueryInterface(riid, ppvOut);
|
|
}
|
|
|
|
if (NULL != *ppvOut)
|
|
{
|
|
((LPUNKNOWN)*ppvOut)->AddRef();
|
|
hResult = NOERROR;
|
|
}
|
|
|
|
return hResult;
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG)
|
|
DiskQuotaUserDisp::AddRef(
|
|
VOID
|
|
)
|
|
{
|
|
ULONG ulReturn = m_cRef + 1;
|
|
|
|
DBGPRINT((DM_COM, DL_HIGH, TEXT("DiskQuotaUserDisp::AddRef, 0x%08X %d -> %d"),
|
|
this, ulReturn - 1, ulReturn));
|
|
|
|
InterlockedIncrement(&m_cRef);
|
|
|
|
return ulReturn;
|
|
}
|
|
|
|
|
|
STDMETHODIMP_(ULONG)
|
|
DiskQuotaUserDisp::Release(
|
|
VOID
|
|
)
|
|
{
|
|
ULONG ulReturn = m_cRef - 1;
|
|
|
|
DBGPRINT((DM_COM, DL_HIGH, TEXT("DiskQuotaUserDisp::Release, 0x%08X %d -> %d"),
|
|
this, ulReturn + 1, ulReturn));
|
|
|
|
if (InterlockedDecrement(&m_cRef) == 0)
|
|
{
|
|
delete this;
|
|
ulReturn = 0;
|
|
}
|
|
return ulReturn;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// IDispatch::GetIDsOfNames
|
|
//
|
|
STDMETHODIMP
|
|
DiskQuotaUserDisp::GetIDsOfNames(
|
|
REFIID riid,
|
|
OLECHAR **rgszNames,
|
|
UINT cNames,
|
|
LCID lcid,
|
|
DISPID *rgDispId
|
|
)
|
|
{
|
|
DBGTRACE((DM_USER, DL_LOW, TEXT("DiskQuotaUserDisp::GetIDsOfNames")));
|
|
//
|
|
// Let our dispatch object handle this.
|
|
//
|
|
return m_Dispatch.GetIDsOfNames(riid,
|
|
rgszNames,
|
|
cNames,
|
|
lcid,
|
|
rgDispId);
|
|
}
|
|
|
|
|
|
//
|
|
// IDispatch::GetTypeInfo
|
|
//
|
|
STDMETHODIMP
|
|
DiskQuotaUserDisp::GetTypeInfo(
|
|
UINT iTInfo,
|
|
LCID lcid,
|
|
ITypeInfo **ppTypeInfo
|
|
)
|
|
{
|
|
DBGTRACE((DM_USER, DL_LOW, TEXT("DiskQuotaUserDisp::GetTypeInfo")));
|
|
//
|
|
// Let our dispatch object handle this.
|
|
//
|
|
return m_Dispatch.GetTypeInfo(iTInfo, lcid, ppTypeInfo);
|
|
}
|
|
|
|
|
|
//
|
|
// IDispatch::GetTypeInfoCount
|
|
//
|
|
STDMETHODIMP
|
|
DiskQuotaUserDisp::GetTypeInfoCount(
|
|
UINT *pctinfo
|
|
)
|
|
{
|
|
DBGTRACE((DM_USER, DL_LOW, TEXT("DiskQuotaUserDisp::GetTypeInfoCount")));
|
|
//
|
|
// Let our dispatch object handle this.
|
|
//
|
|
return m_Dispatch.GetTypeInfoCount(pctinfo);
|
|
}
|
|
|
|
|
|
//
|
|
// IDispatch::Invoke
|
|
//
|
|
STDMETHODIMP
|
|
DiskQuotaUserDisp::Invoke(
|
|
DISPID dispIdMember,
|
|
REFIID riid,
|
|
LCID lcid,
|
|
WORD wFlags,
|
|
DISPPARAMS *pDispParams,
|
|
VARIANT *pVarResult,
|
|
EXCEPINFO *pExcepInfo,
|
|
UINT *puArgErr
|
|
)
|
|
{
|
|
DBGTRACE((DM_USER, DL_LOW, TEXT("DiskQuotaUserDisp::Invoke")));
|
|
DBGPRINT((DM_USER, DL_LOW, TEXT("DispId = %d"), dispIdMember));
|
|
DBGPRINTIID(DM_USER, DL_LOW, riid);
|
|
//
|
|
// Let our dispatch object handle this.
|
|
//
|
|
return m_Dispatch.Invoke(dispIdMember,
|
|
riid,
|
|
lcid,
|
|
wFlags,
|
|
pDispParams,
|
|
pVarResult,
|
|
pExcepInfo,
|
|
puArgErr);
|
|
}
|
|
|
|
|
|
//
|
|
// Return user object's unique ID.
|
|
//
|
|
STDMETHODIMP
|
|
DiskQuotaUserDisp::get_ID(
|
|
long *pID
|
|
)
|
|
{
|
|
return m_pUser->GetID((ULONG *)pID);
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
DiskQuotaUserDisp::get_AccountContainerName(
|
|
BSTR *pContainerName
|
|
)
|
|
{
|
|
TCHAR szName[MAX_DOMAIN] = { TEXT('\0') };
|
|
HRESULT hr = m_pUser->GetName(szName, ARRAYSIZE(szName),
|
|
NULL, 0,
|
|
NULL, 0);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
*pContainerName = SysAllocString(szName);
|
|
if (NULL == *pContainerName)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
DiskQuotaUserDisp::get_LogonName(
|
|
BSTR *pLogonName
|
|
)
|
|
{
|
|
TCHAR szName[MAX_USERNAME] = { TEXT('\0') };
|
|
HRESULT hr = m_pUser->GetName(NULL, 0,
|
|
szName, ARRAYSIZE(szName),
|
|
NULL, 0);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
*pLogonName = SysAllocString(szName);
|
|
if (NULL == *pLogonName)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
DiskQuotaUserDisp::get_DisplayName(
|
|
BSTR *pDisplayName
|
|
)
|
|
{
|
|
TCHAR szName[MAX_FULL_USERNAME] = { TEXT('\0') };
|
|
HRESULT hr = m_pUser->GetName(NULL, 0,
|
|
NULL, 0,
|
|
szName, ARRAYSIZE(szName));
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
*pDisplayName = SysAllocString(szName);
|
|
if (NULL == *pDisplayName)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
DiskQuotaUserDisp::get_QuotaThreshold(
|
|
double *pThreshold
|
|
)
|
|
{
|
|
LONGLONG llValue;
|
|
HRESULT hr = m_pUser->GetQuotaThreshold(&llValue);
|
|
if (SUCCEEDED(hr))
|
|
*pThreshold = (double)llValue;
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
DiskQuotaUserDisp::put_QuotaThreshold(
|
|
double Threshold
|
|
)
|
|
{
|
|
if (MAXLONGLONG < Threshold)
|
|
return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
|
|
|
|
return m_pUser->SetQuotaThreshold((LONGLONG)Threshold, TRUE);
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
DiskQuotaUserDisp::get_QuotaThresholdText(
|
|
BSTR *pThresholdText
|
|
)
|
|
{
|
|
TCHAR szValue[40];
|
|
HRESULT hr = m_pUser->GetQuotaThresholdText(szValue, ARRAYSIZE(szValue));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
*pThresholdText = SysAllocString(szValue);
|
|
if (NULL == *pThresholdText)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
DiskQuotaUserDisp::get_QuotaLimit(
|
|
double *pQuotaLimit
|
|
)
|
|
{
|
|
LONGLONG llValue;
|
|
HRESULT hr = m_pUser->GetQuotaLimit(&llValue);
|
|
|
|
if (SUCCEEDED(hr))
|
|
*pQuotaLimit = (double)llValue;
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
DiskQuotaUserDisp::put_QuotaLimit(
|
|
double Limit
|
|
)
|
|
{
|
|
if (MAXLONGLONG < Limit)
|
|
return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
|
|
|
|
return m_pUser->SetQuotaLimit((LONGLONG)Limit, TRUE);
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
DiskQuotaUserDisp::get_QuotaLimitText(
|
|
BSTR *pLimitText
|
|
)
|
|
{
|
|
TCHAR szValue[40];
|
|
HRESULT hr = m_pUser->GetQuotaLimitText(szValue, ARRAYSIZE(szValue));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
*pLimitText = SysAllocString(szValue);
|
|
if (NULL == *pLimitText)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
DiskQuotaUserDisp::get_QuotaUsed(
|
|
double *pUsed
|
|
)
|
|
{
|
|
LONGLONG llValue;
|
|
HRESULT hr = m_pUser->GetQuotaUsed(&llValue);
|
|
if (SUCCEEDED(hr))
|
|
*pUsed = (double)llValue;
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
DiskQuotaUserDisp::get_QuotaUsedText(
|
|
BSTR *pUsedText
|
|
)
|
|
{
|
|
TCHAR szValue[40];
|
|
HRESULT hr = m_pUser->GetQuotaUsedText(szValue, ARRAYSIZE(szValue));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
*pUsedText = SysAllocString(szValue);
|
|
if (NULL == *pUsedText)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DiskQuotaUserDisp::get_AccountStatus(
|
|
AccountStatusConstants *pStatus
|
|
)
|
|
{
|
|
DWORD dwStatus;
|
|
HRESULT hr = m_pUser->GetAccountStatus(&dwStatus);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
*pStatus = (AccountStatusConstants)dwStatus;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
//
|
|
// Methods.
|
|
//
|
|
STDMETHODIMP
|
|
DiskQuotaUserDisp::Invalidate(
|
|
void
|
|
)
|
|
{
|
|
return m_pUser->Invalidate();
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef NEVER
|
|
// ----------------------------------------------------------------------------
|
|
// OBSOLETE CODE
|
|
// ----------------------------------------------------------------------------
|
|
//
|
|
// I originally provided the GetSidString code in the IDiskQuotaUser interface.
|
|
// It was useful during development but I decided that it would be
|
|
// relatively useless to most users of the interface. If they want to
|
|
// format the SID as a string, they can learn about it on MSDN. That's
|
|
// where I got the original code (See in dskquota\common\utils.cpp).
|
|
// I've left it here in case a need is ever identified.
|
|
//
|
|
// [brianau - 08/05/97]
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: DiskQuotaUser::GetSidString
|
|
|
|
Description: Retrieves the account SID from the user object in character
|
|
format.
|
|
|
|
Arguments:
|
|
pszBuffer - Address of destination buffer for account SID string.
|
|
|
|
cchBuffer - Size of destination buffer in characters.
|
|
|
|
Returns:
|
|
NOERROR - Success.
|
|
E_INVALIDARG - pszBuffer arg is NULL.
|
|
ERROR_INSUFFICIENT_BUFFER (hr) - Caller's buffer is too small.
|
|
ERROR_LOCK_FAILED (hr) - Failed to lock user object.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
07/23/96 Initial creation. BrianAu
|
|
12/10/96 Added class-scope user lock. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP
|
|
DiskQuotaUser::GetSidString(
|
|
LPWSTR pszBuffer,
|
|
DWORD cchBuffer
|
|
)
|
|
{
|
|
HRESULT hResult = NOERROR;
|
|
|
|
if (NULL == pszBuffer)
|
|
return E_INVALIDARG;
|
|
|
|
if (!DiskQuotaUser::Lock())
|
|
{
|
|
hResult = HRESULT_FROM_WIN32(ERROR_LOCK_FAILED);
|
|
}
|
|
else
|
|
{
|
|
DWORD cchSid = cchBuffer;
|
|
if (!SidToString(m_pSid, pszBuffer, &cchSid))
|
|
hResult = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
|
|
|
|
DiskQuotaUser::ReleaseLock();
|
|
}
|
|
|
|
return hResult;
|
|
}
|
|
|
|
|
|
#endif // NEVER
|