890 lines
28 KiB
C++
890 lines
28 KiB
C++
///////////////////////////////////////////////////////////////////////////////
|
|
/* File: fsobject.cpp
|
|
|
|
Description: Contains member function definitions for class FSObject and
|
|
it's derived subclasses.
|
|
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
05/22/96 Initial creation. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
#include "pch.h" // PCH
|
|
#pragma hdrstop
|
|
|
|
#include "dskquota.h"
|
|
#include "fsobject.h"
|
|
#include "pathstr.h"
|
|
|
|
//
|
|
// Verify that build is UNICODE.
|
|
//
|
|
#if !defined(UNICODE)
|
|
# error This module must be compiled UNICODE.
|
|
#endif
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: FSObject::~FSObject
|
|
|
|
Description: Destructor. Frees object's name buffer.
|
|
|
|
Arguments: None.
|
|
|
|
Returns: Nothing.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
05/22/96 Initial creation. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
FSObject::~FSObject(
|
|
VOID
|
|
)
|
|
{
|
|
DBGTRACE((DM_CONTROL, DL_MID, TEXT("FSObject::~FSObject")));
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: FSObject::AddRef
|
|
|
|
Description: Increments object reference count.
|
|
Note this is not a member of IUnknown; but it works the same.
|
|
|
|
Arguments: None.
|
|
|
|
Returns: New reference count value.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
05/22/96 Initial creation. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
ULONG
|
|
FSObject::AddRef(
|
|
VOID
|
|
)
|
|
{
|
|
DBGTRACE((DM_CONTROL, DL_LOW, TEXT("FSObject::AddRef")));
|
|
DBGPRINT((DM_CONTROL, DL_LOW, TEXT("\t0x%08X %d -> %d"),
|
|
this, m_cRef, m_cRef + 1));
|
|
|
|
ULONG ulReturn = m_cRef + 1;
|
|
InterlockedIncrement(&m_cRef);
|
|
|
|
return ulReturn;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: FSObject::Release
|
|
|
|
Description: Decrements object reference count. If count drops to 0,
|
|
object is deleted. Note this is not a member of IUnknown; but it
|
|
works the same.
|
|
|
|
Arguments: None.
|
|
|
|
Returns: New reference count value.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
05/22/96 Initial creation. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
ULONG
|
|
FSObject::Release(
|
|
VOID
|
|
)
|
|
{
|
|
DBGTRACE((DM_CONTROL, DL_LOW, TEXT("FSObject::Release")));
|
|
DBGPRINT((DM_CONTROL, 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: FSObject::ObjectSupportsQuotas
|
|
|
|
Description: Determine a file system object's type (and locality) from
|
|
it's name string.
|
|
|
|
Arguments:
|
|
pszFSObjName - Volume root name. (i.e. "C:\", "\\scratch\scratch").
|
|
|
|
Returns:
|
|
S_OK - Success. Supports quotas.
|
|
ERROR_NOT_SUPPORTED (hr) - File system doesn't support quotas.
|
|
Other win32 error - Couldn't get volume information.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
05/24/96 Initial creation. BrianAu
|
|
08/16/96 Added pSupportsQuotas. BrianAu
|
|
12/05/96 Disabled check for $DeadMeat volume label. BrianAu
|
|
Leave the code in place for a while. I'll remove
|
|
it later when we're sure it's not needed.
|
|
07/03/97 Changed name from ObjectTypeFromName. BrianAu
|
|
Changed logic to indicate reason for not supporting
|
|
quotas.
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
FSObject::ObjectSupportsQuotas(
|
|
LPCTSTR pszFSObjName
|
|
)
|
|
{
|
|
DBGTRACE((DM_CONTROL, DL_MID, TEXT("FSObject::ObjectSupportsQuotas")));
|
|
DBGPRINT((DM_CONTROL, DL_MID, TEXT("\tobject = \"%s\""), pszFSObjName ? pszFSObjName : TEXT("<null>")));
|
|
|
|
HRESULT hr = E_FAIL;
|
|
DWORD dwFileSysFlags = 0;
|
|
TCHAR szFileSysName[MAX_PATH];
|
|
|
|
DBGASSERT((NULL != pszFSObjName));
|
|
|
|
if (GetVolumeInformation(
|
|
pszFSObjName,
|
|
NULL, 0,
|
|
NULL, 0,
|
|
&dwFileSysFlags,
|
|
szFileSysName,
|
|
ARRAYSIZE(szFileSysName)))
|
|
{
|
|
//
|
|
// Does the file system support quotas?
|
|
//
|
|
if (0 != (dwFileSysFlags & FILE_VOLUME_QUOTAS))
|
|
{
|
|
//
|
|
// Yes, it does.
|
|
//
|
|
hr = S_OK;
|
|
DBGPRINT((DM_CONTROL, DL_LOW, TEXT("Vol \"%s\" supports quotas"), pszFSObjName));
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Doesn't support quotas.
|
|
//
|
|
hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
|
|
DBGPRINT((DM_CONTROL, DL_HIGH, TEXT("File system \"%s\" on \"%s\" doesn't support quotas."),
|
|
szFileSysName, pszFSObjName));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DWORD dwErr = GetLastError();
|
|
hr = HRESULT_FROM_WIN32(dwErr);
|
|
DBGERROR((TEXT("Error %d calling GetVolumeInformation for \"%s\""), dwErr, pszFSObjName));
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: FSObject::Create
|
|
|
|
Description: 2 overloaded functions.
|
|
Static functions for creating a File System object of the
|
|
proper type. Clients call Create with an object name string or
|
|
a reference to an existing FSObject instance.
|
|
|
|
Arguments:
|
|
pszFSObjName - Address of volume root string.
|
|
|
|
ppNewObject - Address of FSObject pointer to accept the address of the
|
|
new file system object.
|
|
|
|
ObjToClone - Reference to file system object to be cloned.
|
|
|
|
Returns:
|
|
NOERROR - Success.
|
|
E_OUTOFMEMORY - Insufficient memory.
|
|
ERROR_ACCESS_DENIED (hr) - Insufficient access to open device.
|
|
ERROR_FILE_NOT_FOUND (hr) - Disk device not found.
|
|
ERROR_INVALID_NAME (hr) - Object name is invalid.
|
|
ERROR_NOT_SUPPORTED (hr) - Volume doesn't support quotas.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
05/23/96 Initial creation. BrianAu
|
|
09/05/96 Added exception handling. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
FSObject::Create(
|
|
LPCTSTR pszFSObjName,
|
|
DWORD dwAccess,
|
|
FSObject **ppNewObject
|
|
)
|
|
{
|
|
DBGTRACE((DM_CONTROL, DL_MID, TEXT("FSObject::Create")));
|
|
DBGPRINT((DM_CONTROL, DL_MID, TEXT("\tVol = \"%s\""), pszFSObjName ? pszFSObjName : TEXT("<null>")));
|
|
HRESULT hr = NOERROR;
|
|
|
|
DBGASSERT((NULL != pszFSObjName));
|
|
DBGASSERT((NULL != ppNewObject));
|
|
|
|
*ppNewObject = NULL;
|
|
|
|
FSObject *pNewObject = NULL;
|
|
|
|
try
|
|
{
|
|
hr = FSObject::ObjectSupportsQuotas(pszFSObjName);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = FSObject_CreateLocalVolume(pszFSObjName, &pNewObject);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Do any subclass-specific initialization.
|
|
// i.e.: Volume opens the volume device.
|
|
//
|
|
hr = pNewObject->Initialize(dwAccess);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Return ptr to caller.
|
|
//
|
|
DBGPRINT((DM_CONTROL, DL_MID, TEXT("FSObject created")));
|
|
pNewObject->AddRef();
|
|
*ppNewObject = pNewObject;
|
|
}
|
|
else
|
|
{
|
|
DBGPRINT((DM_CONTROL, DL_MID, TEXT("FSObject create FAILED with error 0x%08X"), hr));
|
|
delete pNewObject;
|
|
pNewObject = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch(CAllocException& e)
|
|
{
|
|
DBGERROR((TEXT("Insufficient memory exception")));
|
|
delete pNewObject; // Will also free name if necessary.
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Version to clone an existing FSObject.
|
|
//
|
|
HRESULT
|
|
FSObject::Create(
|
|
const FSObject& ObjectToClone,
|
|
FSObject **ppNewObject
|
|
)
|
|
{
|
|
return FSObject::Create(ObjectToClone.m_strFSObjName,
|
|
ObjectToClone.m_dwAccessRights,
|
|
ppNewObject);
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: FSObject::GetName
|
|
|
|
Description: Retrieves the file system object's name string.
|
|
|
|
Arguments:
|
|
pszBuffer - Address of buffer to accept name string.
|
|
|
|
cchBuffer - Size of destination buffer in characters.
|
|
|
|
Returns:
|
|
NOERROR - Success.
|
|
ERROR_INSUFFICIENT_BUFFER - Destination buffer is too small for name.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
05/24/96 Initial creation. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
HRESULT FSObject::GetName(LPTSTR pszBuffer, ULONG cchBuffer) const
|
|
{
|
|
HRESULT hr = NOERROR;
|
|
|
|
DBGASSERT((NULL != pszBuffer));
|
|
if ((ULONG)m_strFSObjName.Length() < cchBuffer)
|
|
lstrcpyn(pszBuffer, m_strFSObjName, cchBuffer);
|
|
else
|
|
{
|
|
*pszBuffer = TEXT('\0');
|
|
hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//
|
|
// This function was created to fix bug 365936.
|
|
// Class FSObject has a CPath member who's constructor
|
|
// can throw CAllocException. Because of this, we
|
|
// need to isolate this construction operation from
|
|
// other FSObject code so that we don't try to delete
|
|
// an FSObject object that has already been destroyed
|
|
// by the constructor's call stack unwinding process.
|
|
//
|
|
HRESULT
|
|
FSObject_CreateLocalVolume(
|
|
LPCTSTR pszVolumeName,
|
|
FSObject **ppObject
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
*ppObject = NULL;
|
|
|
|
try
|
|
{
|
|
FSObject *pNewObject = new FSLocalVolume(pszVolumeName);
|
|
*ppObject = pNewObject;
|
|
}
|
|
catch(CAllocException& e)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: FSVolume::~FSVolume
|
|
|
|
Description: Destructor. Closes volume handle.
|
|
|
|
Arguments: None.
|
|
|
|
Returns: Nothing.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
05/24/96 Initial creation. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
FSVolume::~FSVolume(
|
|
VOID
|
|
)
|
|
{
|
|
DBGTRACE((DM_CONTROL, DL_MID, TEXT("FSVolume::~FSVolume")));
|
|
if (INVALID_HANDLE_VALUE != m_hVolume)
|
|
CloseHandle(m_hVolume);
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: FSVolume::Initialize
|
|
|
|
Description: Initializes a volume object by opening the NTFS volume.
|
|
|
|
Arguments:
|
|
dwAccess - Desired access. GENERIC_READ, GENERIC_WRITE.
|
|
|
|
Returns:
|
|
NOERROR - Success.
|
|
ERROR_ACCESS_DENIED (hr) - Insufficient access to open device.
|
|
ERROR_FILE_NOT_FOUND (hr) - Disk device not found.
|
|
ERROR_INVALID_NAME (hr) - Invalid path string.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
05/24/96 Initial creation. BrianAu
|
|
08/11/96 Added access right handling. BrianAu
|
|
08/16/96 Added device name formatting. BrianAu
|
|
07/03/97 Changed so caller passes in desired access. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
HRESULT FSVolume::Initialize(
|
|
DWORD dwAccess
|
|
)
|
|
{
|
|
DBGTRACE((DM_CONTROL, DL_MID, TEXT("FSVolume::Initialize")));
|
|
DBGPRINT((DM_CONTROL, DL_MID, TEXT("\tdwAccess = 0x%08X"), dwAccess));
|
|
|
|
HRESULT hr = NOERROR;
|
|
|
|
//
|
|
// Close the device if it's open.
|
|
//
|
|
if (INVALID_HANDLE_VALUE != m_hVolume)
|
|
CloseHandle(m_hVolume);
|
|
|
|
//
|
|
// Create a path to the actual quota file on the volume.
|
|
// This string is appended to the existing "volume name" we already
|
|
// have.
|
|
//
|
|
CPath strQuotaFile(m_strFSObjName);
|
|
strQuotaFile.AddBackslash();
|
|
strQuotaFile += CString("$Extend\\$Quota:$Q:$INDEX_ALLOCATION");
|
|
|
|
m_hVolume = CreateFile(strQuotaFile,
|
|
dwAccess,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_FLAG_BACKUP_SEMANTICS,
|
|
NULL);
|
|
|
|
if (INVALID_HANDLE_VALUE == m_hVolume)
|
|
{
|
|
//
|
|
// Couldn't open device because...
|
|
// 1. I/O error
|
|
// 2. File (device) not found.
|
|
// 3. Access denied.
|
|
//
|
|
DWORD dwErr = GetLastError();
|
|
hr = HRESULT_FROM_WIN32(dwErr);
|
|
DBGERROR((TEXT("Error %d opening quota file \"%s\""), dwErr, strQuotaFile.Cstr()));
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Save access granted to caller. Will be used to validate
|
|
// operation requests later.
|
|
//
|
|
DBGPRINT((DM_CONTROL, DL_MID, TEXT("Quota file \"%s\" open with access 0x%08X"), strQuotaFile.Cstr(), dwAccess));
|
|
m_dwAccessRights = dwAccess;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: FSVolume::QueryObjectQuotaInformation
|
|
|
|
Description: Retrieves quota information for the volume. This includes
|
|
default quota threshold, default quota limit and system control flags.
|
|
|
|
Arguments:
|
|
poi - Address of object information buffer. This type contains
|
|
a subset of the information in FILE_FS_CONTROL_INFORMATION
|
|
(defined in ntioapi.h).
|
|
|
|
Returns:
|
|
NOERROR - Success.
|
|
ERROR_ACCESS_DENIED (hr) - No READ access to quota device.
|
|
Other - NTFS subsystem failure result.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
05/24/96 Initial creation. BrianAu
|
|
08/11/96 Added access control. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
FSVolume::QueryObjectQuotaInformation(
|
|
PDISKQUOTA_FSOBJECT_INFORMATION poi
|
|
)
|
|
{
|
|
DBGTRACE((DM_CONTROL, DL_MID, TEXT("FSVolume::QueryObjectQuotaInformation")));
|
|
HRESULT hr = E_FAIL;
|
|
|
|
if (!GrantedAccess(GENERIC_READ))
|
|
{
|
|
DBGPRINT((DM_CONTROL, DL_MID, TEXT("Access denied reading quota info")));
|
|
hr = HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
|
|
}
|
|
else
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
IO_STATUS_BLOCK iosb;
|
|
FILE_FS_CONTROL_INFORMATION ControlInfo;
|
|
|
|
status = NtQueryVolumeInformationFile(
|
|
m_hVolume,
|
|
&iosb,
|
|
&ControlInfo,
|
|
sizeof(ControlInfo),
|
|
FileFsControlInformation);
|
|
|
|
if (STATUS_SUCCESS == status)
|
|
{
|
|
//
|
|
// Update caller's buffer with quota control data.
|
|
//
|
|
poi->DefaultQuotaThreshold = ControlInfo.DefaultQuotaThreshold.QuadPart;
|
|
poi->DefaultQuotaLimit = ControlInfo.DefaultQuotaLimit.QuadPart;
|
|
poi->FileSystemControlFlags = ControlInfo.FileSystemControlFlags;
|
|
hr = NOERROR;
|
|
}
|
|
else
|
|
{
|
|
DBGERROR((TEXT("NtQueryVolumeInformationFile failed with NTSTATUS 0x%08X"), status));
|
|
hr = HResultFromNtStatus(status);
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: FSVolume::SetObjectQuotaInformation
|
|
|
|
Description: Writes new quota information to the volume. This includes
|
|
default quota threshold, default quota limit and system control flags.
|
|
|
|
Arguments:
|
|
poi - Address of object information buffer. This type contains
|
|
a subset of the information in FILE_FS_CONTROL_INFORMATION
|
|
(defined in ntioapi.h).
|
|
|
|
dwChangeMask - Mask specifying which elements in *poi to write to disk.
|
|
Can be any combination of:
|
|
FSObject::ChangeState
|
|
FSObject::ChangeLogFlags
|
|
FSObject::ChangeThreshold
|
|
FSObject::ChangeLimit
|
|
|
|
Returns:
|
|
NOERROR - Success.
|
|
ERROR_ACCESS_DENIED (hr) - No WRITE access to quota device.
|
|
Other - NTFS subsystem failure result.
|
|
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
05/24/96 Initial creation. BrianAu
|
|
08/11/96 Added access control. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
FSVolume::SetObjectQuotaInformation(
|
|
PDISKQUOTA_FSOBJECT_INFORMATION poi,
|
|
DWORD dwChangeMask
|
|
) const
|
|
{
|
|
DBGTRACE((DM_CONTROL, DL_MID, TEXT("FSVolume::SetObjectQuotaInformation")));
|
|
HRESULT hr = E_FAIL;
|
|
|
|
if (!GrantedAccess(GENERIC_WRITE))
|
|
{
|
|
DBGPRINT((DM_CONTROL, DL_MID, TEXT("Access denied setting quota info")));
|
|
hr = HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
|
|
}
|
|
else
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
IO_STATUS_BLOCK iosb;
|
|
FILE_FS_CONTROL_INFORMATION ControlInfo;
|
|
|
|
//
|
|
// First read current info from disk.
|
|
// Then replace whatever we're changing.
|
|
//
|
|
status = NtQueryVolumeInformationFile(
|
|
m_hVolume,
|
|
&iosb,
|
|
&ControlInfo,
|
|
sizeof(ControlInfo),
|
|
FileFsControlInformation);
|
|
|
|
if (STATUS_SUCCESS == status)
|
|
{
|
|
//
|
|
// Only alter those values specified in dwChangeMask.
|
|
//
|
|
if (FSObject::ChangeState & dwChangeMask)
|
|
{
|
|
ControlInfo.FileSystemControlFlags &= ~DISKQUOTA_STATE_MASK;
|
|
ControlInfo.FileSystemControlFlags |= (poi->FileSystemControlFlags & DISKQUOTA_STATE_MASK);
|
|
}
|
|
if (FSObject::ChangeLogFlags & dwChangeMask)
|
|
{
|
|
ControlInfo.FileSystemControlFlags &= ~DISKQUOTA_LOGFLAG_MASK;
|
|
ControlInfo.FileSystemControlFlags |= (poi->FileSystemControlFlags & DISKQUOTA_LOGFLAG_MASK);
|
|
}
|
|
if (FSObject::ChangeThreshold & dwChangeMask)
|
|
{
|
|
ControlInfo.DefaultQuotaThreshold.QuadPart = poi->DefaultQuotaThreshold;
|
|
}
|
|
if (FSObject::ChangeLimit & dwChangeMask)
|
|
{
|
|
ControlInfo.DefaultQuotaLimit.QuadPart = poi->DefaultQuotaLimit;
|
|
}
|
|
|
|
status = NtSetVolumeInformationFile(
|
|
m_hVolume,
|
|
&iosb,
|
|
&ControlInfo,
|
|
sizeof(ControlInfo),
|
|
FileFsControlInformation);
|
|
|
|
if (STATUS_SUCCESS == status)
|
|
{
|
|
hr = NOERROR;
|
|
}
|
|
else
|
|
{
|
|
DBGERROR((TEXT("NtSetVolumeInformationFile failed with NTSTATUS = 0x%08X"), status));
|
|
hr = HResultFromNtStatus(status);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DBGERROR((TEXT("NtQueryVolumeInformationFile failed with NTSTATUS = 0x%08X"), status));
|
|
hr = HResultFromNtStatus(status);
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: FSVolume::QueryUserQuotaInformation
|
|
|
|
Description: Retrieves user quota information for the volume. This includes
|
|
quota threshold and quota limit. This function works like an enumerator.
|
|
Repeated calls will return multiple user records.
|
|
|
|
Arguments:
|
|
pBuffer - Address of buffer to receive quota information.
|
|
|
|
cbBuffer - Number of bytes in buffer.
|
|
|
|
bReturnSingleEntry - TRUE = Return only one record from quota file.
|
|
FALSE = Return as many whole entries as possible
|
|
in buffer.
|
|
|
|
pSidList [optional] - Address of SID list identifying users to obtain
|
|
information for. Specify NULL to include all users.
|
|
|
|
cbSidList [optional] - Number of bytes in sid list. Ignored if pSidList
|
|
is NULL.
|
|
|
|
pStartSid [optional] - Address of SID identifying which user is to start
|
|
the enumeration. Specify NULL to start with current user in
|
|
enumeration.
|
|
|
|
bRestartScan - TRUE = restart scan from first user in the SID list or
|
|
the entire file if pSidList is NULL.
|
|
FALSE = Continue enumeration from current user record.
|
|
|
|
Returns:
|
|
NOERROR - Success.
|
|
ERROR_NO_MORE_ITEMS - Read last entry in quota file.
|
|
ERROR_ACCESS_DENIED (hr) - No READ access to quota device.
|
|
Other - Quota subsystem error.
|
|
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
05/24/96 Initial creation. BrianAu
|
|
08/11/96 Added access control. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
FSVolume::QueryUserQuotaInformation(
|
|
PVOID pBuffer,
|
|
ULONG cbBuffer,
|
|
BOOL bReturnSingleEntry,
|
|
PVOID pSidList,
|
|
ULONG cbSidList,
|
|
PSID pStartSid,
|
|
BOOL bRestartScan
|
|
)
|
|
{
|
|
DBGTRACE((DM_CONTROL, DL_MID, TEXT("FSVolume::QueryUserQuotaInformation")));
|
|
HRESULT hr = E_FAIL;
|
|
|
|
DBGASSERT((NULL != pBuffer));
|
|
|
|
if (!GrantedAccess(GENERIC_READ))
|
|
{
|
|
DBGPRINT((DM_CONTROL, DL_MID, TEXT("Access denied querying user quota info")));
|
|
hr = HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
|
|
}
|
|
else
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
IO_STATUS_BLOCK iosb;
|
|
|
|
status = NtQueryQuotaInformationFile(
|
|
m_hVolume,
|
|
&iosb,
|
|
pBuffer,
|
|
cbBuffer,
|
|
(BOOLEAN)bReturnSingleEntry,
|
|
pSidList,
|
|
cbSidList,
|
|
pStartSid,
|
|
(BOOLEAN)bRestartScan);
|
|
|
|
switch(status)
|
|
{
|
|
case STATUS_SUCCESS:
|
|
hr = NOERROR;
|
|
break;
|
|
|
|
default:
|
|
DBGERROR((TEXT("NtQueryQuotaInformationFile failed with NTSTATUS 0x%08X"), status));
|
|
//
|
|
// Fall through...
|
|
//
|
|
case STATUS_NO_MORE_ENTRIES:
|
|
hr = HResultFromNtStatus(status);
|
|
break;
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: FSVolume::SetUserQuotaInformation
|
|
|
|
Description: Writes new user quota information to the volume. This includes
|
|
quota threshold, and quota limit.
|
|
|
|
Arguments:
|
|
pBuffer - Address of buffer containing quota information.
|
|
|
|
cbBuffer - Number of bytes of data in buffer.
|
|
|
|
Returns:
|
|
NOERROR - Success.
|
|
ERROR_ACCESS_DENIED (hr) - No WRITE access to quota device.
|
|
Or tried to set limit on Administrator.
|
|
Other - Quota subsystem error.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
05/24/96 Initial creation. BrianAu
|
|
08/11/96 Added access control. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
FSVolume::SetUserQuotaInformation(
|
|
PVOID pBuffer,
|
|
ULONG cbBuffer
|
|
) const
|
|
{
|
|
DBGTRACE((DM_CONTROL, DL_MID, TEXT("FSVolume::SetUserQuotaInformation")));
|
|
|
|
HRESULT hr = NOERROR;
|
|
|
|
DBGASSERT((NULL != pBuffer));
|
|
|
|
if (!GrantedAccess(GENERIC_WRITE))
|
|
{
|
|
DBGPRINT((DM_CONTROL, DL_MID, TEXT("Access denied setting user quota info")));
|
|
hr = HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
|
|
}
|
|
else
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
IO_STATUS_BLOCK iosb;
|
|
|
|
status = NtSetQuotaInformationFile(
|
|
m_hVolume,
|
|
&iosb,
|
|
pBuffer,
|
|
cbBuffer);
|
|
|
|
if (STATUS_SUCCESS == status)
|
|
{
|
|
hr = NOERROR;
|
|
}
|
|
else
|
|
{
|
|
DBGERROR((TEXT("NtSetQuotaInformationFile failed with NTSTATUS 0x%08X"), status));
|
|
hr = HResultFromNtStatus(status);
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
//
|
|
// Convert an NTSTATUS value to an HRESULT.
|
|
// This is a simple attempt at converting the most common NTSTATUS values that
|
|
// might be returned from NtQueryxxxxx and NTSetxxxxxx functions. If I've missed
|
|
// some obvious ones, go ahead and add them.
|
|
//
|
|
HRESULT
|
|
FSObject::HResultFromNtStatus(
|
|
NTSTATUS status
|
|
)
|
|
{
|
|
HRESULT hr = E_FAIL; // Default if none matched.
|
|
|
|
static const struct
|
|
{
|
|
NTSTATUS status;
|
|
HRESULT hr;
|
|
} rgXref[] = {
|
|
|
|
{ STATUS_SUCCESS, NOERROR },
|
|
{ STATUS_INVALID_PARAMETER, E_INVALIDARG },
|
|
{ STATUS_NO_MORE_ENTRIES, HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) },
|
|
{ STATUS_ACCESS_DENIED, HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED) },
|
|
{ STATUS_BUFFER_TOO_SMALL, HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) },
|
|
{ STATUS_BUFFER_OVERFLOW, HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW) },
|
|
{ STATUS_INVALID_HANDLE, HRESULT_FROM_WIN32(ERROR_INVALID_HANDLE) },
|
|
{ STATUS_INVALID_DEVICE_REQUEST, HRESULT_FROM_WIN32(ERROR_BAD_DEVICE) },
|
|
{ STATUS_FILE_INVALID, HRESULT_FROM_WIN32(ERROR_DEVICE_NOT_AVAILABLE) }};
|
|
|
|
for (int i = 0; i < ARRAYSIZE(rgXref); i++)
|
|
{
|
|
if (rgXref[i].status == status)
|
|
{
|
|
hr = rgXref[i].hr;
|
|
break;
|
|
}
|
|
}
|
|
return hr;
|
|
}
|