2025-04-27 07:49:33 -04:00

801 lines
21 KiB
C++

// Copyright (c) 2000-2001 Microsoft Corporation, All Rights Reserved
//
// util.cpp - Common utilities for printing out messages
//
//
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <ntobapi.h>
#define _WINNT_ // have what is needed from above
#pragma warning (disable: 4786)
#pragma warning (disable: 4284)
#include <objbase.h>
#include <comdef.h>
#include <stdio.h> //sprintf
#include <stdlib.h>
#include <assert.h>
#include <strstrea.h>
#include <vector>
#include <DskQuota.h>
#include <ntioapi.h>
#include "util.h"
// This function does pretty much all of the
// work this com server was constructed to do -
// it obtains, for the process space that this
// server is running in, the set of mapped
// drives, and for each of these, the following
// information as well:
//
HRESULT GetMappedDisksAndData(
DWORD dwReqProps,
VARIANT* pvarData)
{
HRESULT hr = S_OK;
::SetLastError(ERROR_SUCCESS);
DWORD dwError = ERROR_SUCCESS;
::VariantInit(pvarData);
V_VT(pvarData) = VT_EMPTY;
// Get list of drives...
DWORD dwBuffLen = 0L;
if((dwBuffLen = ::GetLogicalDriveStrings(
0,
NULL)) != 0)
{
LPWSTR wstrDrives = NULL;
try
{
wstrDrives = new WCHAR[dwBuffLen];
if(wstrDrives)
{
DWORD dwTmp;
::ZeroMemory((LPVOID)wstrDrives, dwBuffLen*sizeof(WCHAR));
::SetLastError(ERROR_SUCCESS);
dwTmp = ::GetLogicalDriveStrings(
dwBuffLen,
wstrDrives);
if(dwTmp <= dwBuffLen)
{
// O.K, we now have the drive strings.
// Put only the mapped drives into a vector...
std::vector<_bstr_t> vecMappedDrives;
GetMappedDriveList(
wstrDrives,
vecMappedDrives);
// Now allocate the two dimensional
// safearray that will hold the properties
// for each mapped drive...
SAFEARRAY* saDriveProps = NULL;
SAFEARRAYBOUND rgsabound[2];
rgsabound[0].cElements = PROP_COUNT;
rgsabound[0].lLbound = 0;
rgsabound[1].cElements = vecMappedDrives.size();
rgsabound[1].lLbound = 0;
saDriveProps = ::SafeArrayCreate(
VT_BSTR,
2,
rgsabound);
if(saDriveProps)
{
// For each mapped drive, obtain its
// properties and store in the safearray...
for(long m = 0;
m < vecMappedDrives.size() && SUCCEEDED(hr);
m++)
{
hr = GetMappedDriveInfo(
vecMappedDrives[m],
m,
saDriveProps,
dwReqProps);
}
// And finally package the safearray
// into the outgoing variant.
if(SUCCEEDED(hr))
{
::VariantInit(pvarData);
V_VT(pvarData) = VT_BSTR | VT_ARRAY;
V_ARRAY(pvarData) = saDriveProps;
}
}
else
{
hr = E_OUTOFMEMORY;
}
}
else
{
dwError = ::GetLastError();
hr = HRESULT_FROM_WIN32(dwError);
}
}
else
{
hr = E_OUTOFMEMORY;
}
delete wstrDrives; wstrDrives = NULL;
}
catch(...)
{
if(wstrDrives)
{
delete wstrDrives; wstrDrives = NULL;
}
throw;
}
}
else if(dwBuffLen == 0 &&
(dwError = ::GetLastError()) != ERROR_SUCCESS)
{
hr = HRESULT_FROM_WIN32(dwError);
}
return hr;
}
// Similar to GetMappedDisksAndData, but only
// retrieves info for a single disk.
HRESULT GetSingleMappedDiskAndData(
BSTR bstrDrive,
DWORD dwReqProps,
VARIANT* pvarData)
{
HRESULT hr = S_OK;
::SetLastError(ERROR_SUCCESS);
DWORD dwError = ERROR_SUCCESS;
::VariantInit(pvarData);
V_VT(pvarData) = VT_EMPTY;
// Get list of drives...
DWORD dwBuffLen = 0L;
if((dwBuffLen = ::GetLogicalDriveStrings(
0,
NULL)) != 0)
{
LPWSTR wstrDrives = NULL;
try
{
wstrDrives = new WCHAR[dwBuffLen];
if(wstrDrives)
{
DWORD dwTmp;
::ZeroMemory((LPVOID)wstrDrives, dwBuffLen*sizeof(WCHAR));
::SetLastError(ERROR_SUCCESS);
dwTmp = ::GetLogicalDriveStrings(
dwBuffLen,
wstrDrives);
if(dwTmp <= dwBuffLen)
{
// O.K, we now have the drive strings.
// Put only the mapped drives into a vector...
std::vector<_bstr_t> vecMappedDrives;
GetMappedDriveList(
wstrDrives,
vecMappedDrives);
// Now allocate the two dimensional
// safearray that will hold the properties
// for each mapped drive...
// Note: in this routine, it is really
// only a one dimensional array, but,
// for code reuse, we'll treat it as a
// two dimensional array with only one
// element in one of the dimensions.
SAFEARRAY* saDriveProps = NULL;
SAFEARRAYBOUND rgsabound[2];
rgsabound[0].cElements = PROP_COUNT;
rgsabound[0].lLbound = 0;
rgsabound[1].cElements = 1; // for code reuse
rgsabound[1].lLbound = 0;
saDriveProps = ::SafeArrayCreate(
VT_BSTR,
2,
rgsabound);
if(saDriveProps)
{
// See if the drive specified is a member
// of the vector.
_bstr_t bstrtTmp = bstrDrive;
bstrtTmp += L"\\";
bool fFoundIt = false;
for(long n = 0;
n < vecMappedDrives.size() && !fFoundIt;
n++)
{
if(_wcsicmp(bstrtTmp, vecMappedDrives[n]) == 0)
{
fFoundIt = true;
n--;
}
}
// For the mapped drive, obtain its
// properties and store in the safearray...
if(fFoundIt)
{
hr = GetMappedDriveInfo(
vecMappedDrives[n],
0, // for code reuse
saDriveProps,
dwReqProps);
// And finally package the safearray
// into the outgoing variant.
::VariantInit(pvarData);
V_VT(pvarData) = VT_BSTR | VT_ARRAY;
V_ARRAY(pvarData) = saDriveProps;
}
}
else
{
hr = E_OUTOFMEMORY;
}
}
else
{
dwError = ::GetLastError();
hr = HRESULT_FROM_WIN32(dwError);
}
}
else
{
hr = E_OUTOFMEMORY;
}
delete wstrDrives; wstrDrives = NULL;
}
catch(...)
{
if(wstrDrives)
{
delete wstrDrives; wstrDrives = NULL;
}
throw;
}
}
else if(dwBuffLen == 0 &&
(dwError = ::GetLastError()) != ERROR_SUCCESS)
{
hr = HRESULT_FROM_WIN32(dwError);
}
return hr;
}
void GetMappedDriveList(
LPWSTR wstrDrives,
std::vector<_bstr_t>& vecMappedDrives)
{
for(LPWSTR wstrCurrentDrive = wstrDrives;
*wstrCurrentDrive;
wstrCurrentDrive += (wcslen(wstrCurrentDrive) + 1))
{
_wcsupr(wstrCurrentDrive);
if(::GetDriveType(wstrCurrentDrive) == DRIVE_REMOTE)
{
vecMappedDrives.push_back(wstrCurrentDrive);
}
}
}
HRESULT GetMappedDriveInfo(
LPCWSTR wstrDriveName,
long lDrivePropArrayDriveIndex,
SAFEARRAY* saDriveProps,
DWORD dwReqProps)
{
HRESULT hr = S_OK;
// Right away we can set the device id prop...
hr = SetProperty(
lDrivePropArrayDriveIndex,
PROP_DEVICEID,
wstrDriveName,
saDriveProps);
// If we couldn't even set the device id, it is
// a problem. Otherwise, continue.
if(SUCCEEDED(hr))
{
// Set the other properties if they
// were requested...
// Get Expensive properties now if appropriate.
if(dwReqProps &
(SPIN_DISK |
GET_PROVIDER_NAME))
{
if(dwReqProps & GET_PROVIDER_NAME)
{
GetProviderName(
wstrDriveName,
lDrivePropArrayDriveIndex,
saDriveProps);
}
if(dwReqProps & GET_VOL_INFO)
{
// Obtain volume information
GetDriveVolumeInformation(
wstrDriveName,
lDrivePropArrayDriveIndex,
saDriveProps);
}
if ( dwReqProps &
(PROP_SIZE |
PROP_FREE_SPACE) )
{
GetDriveFreeSpace(
wstrDriveName,
lDrivePropArrayDriveIndex,
saDriveProps);
}
}
}
return hr;
}
HRESULT GetProviderName(
LPCWSTR wstrDriveName,
long lDrivePropArrayDriveIndex,
SAFEARRAY* saDriveProps)
{
HRESULT hr = S_OK;
WCHAR wstrTempDrive[_MAX_PATH] ;
wsprintf(
wstrTempDrive,
L"%c%c",
wstrDriveName[0],
wstrDriveName[1]);
WCHAR wstrProvName[_MAX_PATH];
DWORD dwProvName = sizeof(wstrProvName ) ;
DWORD dwRetCode = WNetGetConnection(
wstrTempDrive,
wstrProvName,
&dwProvName);
if(dwRetCode == NO_ERROR)
{
hr = SetProperty(
lDrivePropArrayDriveIndex,
PROP_PROVIDER_NAME,
wstrProvName,
saDriveProps);
}
else
{
dwRetCode = GetLastError();
if((dwRetCode == ERROR_MORE_DATA) &&
(dwProvName > _MAX_PATH))
{
WCHAR* wstrNewProvName = NULL;
try
{
wstrNewProvName = new WCHAR[dwProvName];
if(wstrNewProvName != NULL)
{
dwRetCode = WNetGetConnection(
wstrTempDrive,
wstrNewProvName,
&dwProvName);
if(dwRetCode == NO_ERROR)
{
hr = SetProperty(
lDrivePropArrayDriveIndex,
PROP_PROVIDER_NAME,
wstrNewProvName,
saDriveProps);
}
else
{
hr = HRESULT_FROM_WIN32(dwRetCode);
}
delete wstrNewProvName;
}
else
{
hr = E_OUTOFMEMORY;
}
}
catch( ... )
{
delete wstrNewProvName;
throw;
}
}
else
{
hr = HRESULT_FROM_WIN32(dwRetCode);
}
}
return hr;
}
HRESULT GetDriveVolumeInformation(
LPCWSTR wstrDriveName,
long lDrivePropArrayDriveIndex,
SAFEARRAY* saDriveProps)
{
HRESULT hr = S_OK;
DWORD dwResult = ERROR_SUCCESS;
WCHAR wstrVolumeName[_MAX_PATH];
WCHAR wstrFileSystem[_MAX_PATH];
WCHAR wstrTmp[_MAX_PATH];
DWORD dwSerialNumber;
DWORD dwMaxComponentLength;
DWORD dwFSFlags;
BOOL fReturn = ::GetVolumeInformation(
wstrDriveName,
wstrVolumeName,
sizeof(wstrVolumeName)/sizeof(WCHAR),
&dwSerialNumber,
&dwMaxComponentLength,
&dwFSFlags,
wstrFileSystem,
sizeof(wstrFileSystem)/sizeof(WCHAR)
);
if(fReturn)
{
// Win32 API will return volume information for all drive types.
SetProperty(
lDrivePropArrayDriveIndex,
PROP_VOLUME_NAME,
wstrVolumeName,
saDriveProps);
SetProperty(
lDrivePropArrayDriveIndex,
PROP_FILE_SYSTEM,
wstrFileSystem,
saDriveProps);
if (dwSerialNumber != 0)
{
WCHAR wstrSerialNumber[_MAX_PATH];
wsprintf(wstrSerialNumber,
L"%.8X",
dwSerialNumber);
SetProperty(
lDrivePropArrayDriveIndex,
PROP_VOLUME_SERIAL_NUMBER,
wstrSerialNumber,
saDriveProps);
}
SetProperty(
lDrivePropArrayDriveIndex,
PROP_COMPRESSED,
STR_FROM_bool(dwFSFlags & FS_VOL_IS_COMPRESSED),
saDriveProps);
SetProperty(
lDrivePropArrayDriveIndex,
PROP_SUPPORTS_FILE_BASED_COMPRESSION,
STR_FROM_bool(dwFSFlags & FS_FILE_COMPRESSION),
saDriveProps);
_ultow(dwMaxComponentLength,
wstrTmp,
10);
SetProperty(
lDrivePropArrayDriveIndex,
PROP_MAXIMUM_COMPONENT_LENGTH,
wstrTmp,
saDriveProps);
SetProperty(
lDrivePropArrayDriveIndex,
PROP_SUPPORTS_DISK_QUOTAS,
STR_FROM_bool(dwFSFlags & FILE_VOLUME_QUOTAS),
saDriveProps);
// To get the state of the volume,
// we need to get the Interface pointer...
IDiskQuotaControlPtr pIQuotaControl;
::SetLastError(ERROR_SUCCESS);
if(SUCCEEDED(CoCreateInstance(
CLSID_DiskQuotaControl,
NULL,
CLSCTX_INPROC_SERVER,
IID_IDiskQuotaControl,
(void **)&pIQuotaControl)))
{
WCHAR wstrVolumePathName[MAX_PATH + 1];
::SetLastError(ERROR_SUCCESS);
BOOL fRetVal = ::GetVolumePathName(
wstrDriveName,
wstrVolumePathName,
MAX_PATH);
if(fRetVal)
{
::SetLastError(ERROR_SUCCESS);
if(SUCCEEDED(pIQuotaControl->Initialize(
wstrVolumePathName,
TRUE)))
{
DWORD dwQuotaState;
::SetLastError(ERROR_SUCCESS);
hr = pIQuotaControl->GetQuotaState(&dwQuotaState);
if(SUCCEEDED(hr))
{
SetProperty(
lDrivePropArrayDriveIndex,
PROP_QUOTAS_INCOMPLETE,
STR_FROM_bool(DISKQUOTA_FILE_INCOMPLETE(dwQuotaState)),
saDriveProps);
SetProperty(
lDrivePropArrayDriveIndex,
PROP_QUOTAS_REBUILDING,
STR_FROM_bool(DISKQUOTA_FILE_REBUILDING(dwQuotaState)),
saDriveProps);
SetProperty(
lDrivePropArrayDriveIndex,
PROP_QUOTAS_DISABLED,
STR_FROM_bool(DISKQUOTA_STATE_DISABLED & dwQuotaState),
saDriveProps);
}
else
{
dwResult = GetLastError();
}
}
else
{
dwResult = GetLastError();
}
}
}
else
{
dwResult = GetLastError();
}
}
else
{
dwResult = GetLastError();
}
// for chkdsk VolumeDirty Property
BOOLEAN fVolumeDirty = FALSE;
BOOL fSuccess = FALSE;
_bstr_t bstrtDosDrive(wstrDriveName);
UNICODE_STRING string;
RtlDosPathNameToNtPathName_U(
(LPCWSTR)bstrtDosDrive,
&string,
NULL,
NULL);
string.Buffer[string.Length/sizeof(WCHAR) - 1] = 0;
_bstr_t nt_drive_name(string.Buffer);
::SetLastError(ERROR_SUCCESS);
fSuccess = IsVolumeDirty(
nt_drive_name,
&fVolumeDirty );
if(fSuccess)
{
SetProperty(
lDrivePropArrayDriveIndex,
PROP_PERFORM_AUTOCHECK,
STR_FROM_bool(!fVolumeDirty),
saDriveProps);
}
if(dwResult != ERROR_SUCCESS)
{
hr = HRESULT_FROM_WIN32(dwResult);
}
return hr;
}
BOOLEAN IsVolumeDirty(
_bstr_t &bstrtNtDriveName,
BOOLEAN *Result)
{
UNICODE_STRING u;
OBJECT_ATTRIBUTES obj;
NTSTATUS status;
IO_STATUS_BLOCK iosb;
HANDLE h;
ULONG r;
BOOLEAN bRetVal = FALSE;
WCHAR wstrNtDriveName[_MAX_PATH];
wcscpy(wstrNtDriveName, bstrtNtDriveName);
u.Length = (USHORT) wcslen(wstrNtDriveName) * sizeof(WCHAR);
u.MaximumLength = u.Length;
u.Buffer = wstrNtDriveName;
InitializeObjectAttributes(&obj, &u, OBJ_CASE_INSENSITIVE, 0, 0);
status = NtOpenFile(
&h,
SYNCHRONIZE | FILE_READ_DATA,
&obj,
&iosb,
FILE_SHARE_READ|FILE_SHARE_WRITE,
FILE_SYNCHRONOUS_IO_ALERT);
if(NT_SUCCESS(status))
{
status = NtFsControlFile(
h, NULL, NULL, NULL,
&iosb,
FSCTL_IS_VOLUME_DIRTY,
NULL, 0,
&r, sizeof(r));
if(NT_SUCCESS(status))
{
#if(_WIN32_WINNT >= 0x0500)
*Result = (BOOLEAN)(r & VOLUME_IS_DIRTY);
#else
*Result = (BOOLEAN)r;
#endif
bRetVal = TRUE;
}
NtClose(h);
}
return bRetVal;
}
HRESULT GetDriveFreeSpace(
LPCWSTR wstrDriveName,
long lDrivePropArrayDriveIndex,
SAFEARRAY* saDriveProps)
{
HRESULT hr = S_OK;
ULARGE_INTEGER uliTotalBytes;
ULARGE_INTEGER uliUserFreeBytes;
ULARGE_INTEGER uliTotalFreeBytes;
::SetLastError(ERROR_SUCCESS);
if(::GetDiskFreeSpaceEx(
wstrDriveName,
&uliUserFreeBytes,
&uliTotalBytes,
&uliTotalFreeBytes))
{
WCHAR wstrTmp[128] = { L'\0' };
SetProperty(
lDrivePropArrayDriveIndex,
PROP_SIZE,
_ui64tow(
uliTotalBytes.QuadPart,
wstrTmp,
10),
saDriveProps);
SetProperty(
lDrivePropArrayDriveIndex,
PROP_FREE_SPACE,
_ui64tow(
uliTotalFreeBytes.QuadPart,
wstrTmp,
10),
saDriveProps);
}
else
{
hr = HRESULT_FROM_WIN32(::GetLastError());
}
return hr;
}
// Sets a property for a given drive
// in the drive safearray.
HRESULT SetProperty(
long lDrivePropArrayDriveIndex,
long lDrivePropArrayPropIndex,
LPCWSTR wstrPropValue,
SAFEARRAY* saDriveProps)
{
HRESULT hr = S_OK;
BSTR bstrTmp = NULL;
try
{
bstrTmp = ::SysAllocString(wstrPropValue);
long ix[2];
ix[0] = lDrivePropArrayPropIndex;
ix[1] = lDrivePropArrayDriveIndex;
hr = ::SafeArrayPutElement(
saDriveProps,
ix,
bstrTmp);
}
catch(...)
{
if(bstrTmp != NULL)
{
::SysFreeString(bstrTmp);
bstrTmp = NULL;
}
throw;
}
return hr;
}