windows-nt/Source/XPSP1/NT/drivers/ftapi/ftman/global.cpp
2020-09-26 16:20:57 +08:00

651 lines
16 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1998 Microsoft Corporation
Module Name:
FTMan
File Name:
Global.cpp
Abstract:
Implementation of useful global functions
Author:
Cristian Teodorescu October 29, 1998
Notes:
Revision History:
--*/
#include "stdafx.h"
#include "FTUtil.h"
#include "Global.h"
#include "Item.h"
#include "MainFrm.h"
#include "Resource.h"
#include <basetyps.h>
#include <mountmgr.h>
#include <winbase.h>
#include <winioctl.h>
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
////////////////////////////////////////////////////////////////////////////
// Display functions
/*
Global function: DisplaySystemErrorMessage
Purpose: Display the last system error message prefixed ( or not ) with another string taken from
our resources explaining the context of the failure
Parameters: [IN] UINT unContextMsgID
The ID of the string that must prefix the system error message. ID in resource.h
Default is 0 which means that the system error shouldn't be prefixed
Return value: TRUE if the functions succeeds
*/
BOOL DisplaySystemErrorMessage( UINT unContextMsgID /* =0 */)
{
MY_TRY
// Get the system error message
LPVOID lpMsgBuf;
if( !::FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuf,
0,
NULL ) ) // Process any inserts in lpMsgBuf.
return FALSE;
CString str;
if( unContextMsgID != 0) // The system error message must be prefixed with another string from the resources of this application
if( !str.LoadString( unContextMsgID ) ) return FALSE;
str += ((LPCTSTR)lpMsgBuf);
LocalFree( lpMsgBuf );
AfxMessageBox(str, MB_ICONSTOP);
return TRUE;
MY_CATCH_AND_THROW
}
/*
Global function: DisplayStatusBarMessage (1)
Purpose: Displays a message in the first pane of the main frame status bar
Parameters: [IN] LPCTSTR lpszMsg
The message to display
Return value: TRUE if the functions succeeds
*/
BOOL DisplayStatusBarMessage( LPCTSTR lpszMsg )
{
MY_TRY
CStatusBar* pStatusBar = ((CMainFrame*)AfxGetMainWnd())->GetStatusBar();
if( !pStatusBar )
return FALSE;
// Use the ID_SEPARATOR pane of the status bar
return pStatusBar->SetPaneText( 5, lpszMsg );
MY_CATCH_AND_THROW
}
/*
Global function: DisplayStatusBarMessage (2)
Purpose: Display a message in the first pane of the main frame status bar
Parameters: [IN] UINT unMsgID
Resource ID of the string to display
Return value: TRUE if the functions succeeds
*/
BOOL DisplayStatusBarMessage( UINT unMsgID )
{
MY_TRY
CString str;
str.LoadString(unMsgID);
return DisplayStatusBarMessage(str);
MY_CATCH_AND_THROW
}
/*
Global function: FormatVolumeSize
Purpose: Format the size of a volume in a "readable" way
( in GB, MB or KB depending on the size range )
Parameters: [OUT] CString& strSize
Reference to the string to receive the formatted size
[IN] LONGLONG llSize
The size to format ( in Bytes )
Return value: -
*/
void FormatVolumeSize( CString& strSize, LONGLONG llSize )
{
MY_TRY
if( llSize >= 0x40000000 ) // 1GB = 2^30 B
strSize.Format(_T("%.2f GB"), ((double)(llSize>>20))/((double)0x400));
else if (llSize >= 0x100000 ) // 1MB = 2^20 B
strSize.Format(_T("%.2f MB"), ((double)(llSize>>10))/((double)0x400));
else
strSize.Format(_T("%.2f KB"), ((double)llSize)/((double)0x400));
MY_CATCH_AND_THROW
}
/*
Global function: CopyW2Str
Purpose: Copy a Unicode character array into a CString
Parameters: [OUT] CString& strDest
Reference to the string to receive the formatted size
[IN] LPWSTR strSource
Unicode character array to be copied
[IN] ULONG ulLength
The number of characters to copy
Return value: -
*/
void CopyW2Str( CString& strDest, LPWSTR strSource, ULONG ulLength )
{
MY_TRY
LPTSTR lpstr = strDest.GetBuffer( ulLength + 1 );
#ifdef UNICODE
memcpy( lpstr, strSource, ulLength * sizeof(WCHAR ) );
#else
WideCharToMultiByte( CP_APP, 0, strSource, ulLength, lpstr, ulLength * sizeof(char), NULL, NULL );
#endif
lpstr[ulLength]=_T('\0');
strDest.ReleaseBuffer();
MY_CATCH_AND_THROW
}
/*
Global function: CopyStr2W
Purpose: Copy a CString content into a Unicode character array
Parameters: [OUT] LPWSTR strDest
Pointer to the buffer to receive the character array. It should be already allocated
[IN] CString& strSource
Reference to the string to be copied
Return value: -
*/
void CopyStr2W( LPWSTR strDest, CString& strSource )
{
MY_TRY
LPTSTR lpstr = strSource.GetBuffer(0);
int nSize = strSource.GetLength();
#ifdef UNICODE
memcpy( strDest, lpstr, nSize * sizeof(WCHAR) );
#else
MultiByteToWideChar( CP_APP, 0, lpstr, nSize, strDest, nSize * sizeof(WCHAR) );
#endif
strDest[nSize] = _T('\0');
strSource.ReleaseBuffer();
MY_CATCH_AND_THROW
}
/*
Global function: OpenVolume
Purpose: Open a volume given its name
The name must be like this "\\?\Volume{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}\"
Parameters: [IN] CString& strVolumeName
Volume name
Return value: HANDLE
Handle of the open volume. INVALID_HANDLE_VALUE if the operation failed
*/
HANDLE OpenVolume( const CString& strVolumeName )
{
return CreateFile( strVolumeName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, INVALID_HANDLE_VALUE );
}
/*
Global function: IsDOSName
Purpose: Decides wether a name is a DOS name i.e. "\DosDevices\X:"
Parameters: [IN] CString& str
The name
Return value: TRUE if it is a DOS name
*/
BOOL IsDOSName( const CString& str )
{
MY_TRY
// "\DosDevices\X:"
return( ( str.GetLength() == 14 ) &&
( str.Left(12) == _T("\\DosDevices\\") ) &&
( str[13] == _T(':') ) );
MY_CATCH_AND_THROW
}
/*
Global function: IsVolumeName
Purpose: Decides wether a name is a volume name i.e. "\??\Volume{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}"
Parameters: [IN] CString& str
The name
Return value: TRUE if it is a volume name
*/
BOOL IsVolumeName( const CString& str )
{
MY_TRY
// "\??\Volume{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}"
return( ( str.GetLength() == 48 ) &&
( str.Left(11) == _T("\\??\\Volume{") ) &&
( str[19] == _T('-') ) &&
( str[24] == _T('-') ) &&
( str[29] == _T('-') ) &&
( str[34] == _T('-') ) &&
( str[47] == _T('}') ) );
MY_CATCH_AND_THROW
}
/*
Global function: QueryDriveLetterAndVolumeName
Purpose: Query the drive letter and the name of the volume given its NT Name
The name will be like this: "\\?\Volume{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}"
Parameters: [IN] CString& strNTName
The NT name of the volume
[OUT] TCHAR& cDriveLetter
The drive letter of the volume
[OUT] CString& strVolumeName
The name ( to be used by FindFirst/FindNext ) of the volume
Return value: TRUE if the function succeeded
*/
BOOL QueryDriveLetterAndVolumeName( CString& strNTName, TCHAR& cDriveLetter, CString& strVolumeName )
{
MY_TRY
cDriveLetter = _T('\0');
strVolumeName = _T("");
if( strNTName.IsEmpty() )
return FALSE;
HANDLE h;
ULONG ulInputSize;
PMOUNTMGR_MOUNT_POINT pInput;
ULONG ulOutputSize;
PMOUNTMGR_MOUNT_POINTS pOutput;
ULONG ulBytes;
BOOL bResult;
USHORT unNTNameLength;
// Open the mount manager
h = CreateFileW(MOUNTMGR_DOS_DEVICE_NAME, GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
INVALID_HANDLE_VALUE);
if (h == INVALID_HANDLE_VALUE)
{
TRACE( _T("Error: Open mount manager failed in GetDriveLetterAndVolumeName\n") );
return FALSE;
}
// Prepare the input structure
unNTNameLength = (USHORT)strNTName.GetLength();
ulInputSize = sizeof(MOUNTMGR_MOUNT_POINT) + ((unNTNameLength + 1)*sizeof(WCHAR));
pInput = (PMOUNTMGR_MOUNT_POINT) LocalAlloc( 0, ulInputSize);
if (!pInput)
{
TRACE( _T("Error: Memory allocation failure in GetDriveLetterAndVolumeName\n") );
CloseHandle(h);
return FALSE;
}
pInput->SymbolicLinkNameLength = 0;
pInput->SymbolicLinkNameOffset = 0;
pInput->UniqueIdOffset = 0;
pInput->UniqueIdLength = 0;
pInput->DeviceNameOffset = sizeof(MOUNTMGR_MOUNT_POINT);
pInput->DeviceNameLength = unNTNameLength * sizeof(WCHAR);
CopyStr2W( (LPWSTR) ((PUCHAR) pInput + pInput->DeviceNameOffset), strNTName );
// Prepare the output structure
ulOutputSize = sizeof(MOUNTMGR_MOUNT_POINTS) + 1024;
pOutput = (PMOUNTMGR_MOUNT_POINTS) LocalAlloc( 0, ulOutputSize);
if (!pOutput)
{
TRACE( _T("Error: Memory allocation failure in GetDriveLetterAndVolumeName\n") );
CloseHandle(h);
LocalFree(pInput);
return FALSE;
}
bResult = DeviceIoControl( h, IOCTL_MOUNTMGR_QUERY_POINTS, pInput, ulInputSize,
pOutput, ulOutputSize, &ulBytes, NULL);
while (!bResult && GetLastError() == ERROR_MORE_DATA)
{
ulOutputSize = pOutput->Size;
LocalFree( pOutput );
pOutput = (PMOUNTMGR_MOUNT_POINTS)(LocalAlloc(0, ulOutputSize ));
if (!pOutput)
{
TRACE( _T("Error: Memory Allocation failure in QueryMountPoints") );
CloseHandle(h);
LocalFree(pInput);
return FALSE;
}
bResult = DeviceIoControl(h, IOCTL_MOUNTMGR_QUERY_POINTS, pInput, ulInputSize,
pOutput, ulOutputSize, &ulBytes, NULL);
}
CloseHandle(h);
LocalFree(pInput);
if( !bResult )
{
TRACE( _T("Error: IOCTL_MOUNTMGR_QUERY_POINTS failure in GetDriveLetterAndVolumeName\n") );
LocalFree(pOutput);
return FALSE;
}
//CStringArray arrMountPointName;
CString strMountPoint;
for( ULONG i=0; i < pOutput->NumberOfMountPoints; i++ )
{
PMOUNTMGR_MOUNT_POINT pMountPoint = &(pOutput->MountPoints[i]);
/*
if (!point->SymbolicLinkNameOffset) {
continue; }
*/
CopyW2Str( strMountPoint, (LPWSTR)((PCHAR)pOutput + pMountPoint->SymbolicLinkNameOffset),
pMountPoint->SymbolicLinkNameLength / sizeof(WCHAR) );
if( IsDOSName( strMountPoint ) ) // i.e. "\DosDevices\X:"
{
// I got the drive letter
cDriveLetter = strMountPoint[12];
}
else if ( IsVolumeName( strMountPoint ) ) // i.e. "\??\Volume{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}"
{
// I got the volume name !!!!
strVolumeName = strMountPoint;
// Make it like this : "\\?\Volume{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}"
strVolumeName.SetAt( 1, _T('\\') );
}
}
LocalFree(pOutput);
return TRUE;
MY_CATCH_AND_THROW
}
/*
Global function: QueryMountListInPath
Purpose: Query the mount manager for all mount paths of the given volumes in a certain path
Each found mount path is added to the corresponding volume in array arrItems ( if any )
Parameters: [IN] CString& strPath
The path to search in
[IN/OUT] CObArray& arrVolumesData
Array of CItemData - Tree items ( volumes ) whose mount paths we are looking for
Return value: -
*/
void QueryMountListInPath( const CString& strPath, CObArray& arrVolumesData )
{
MY_TRY
BOOL bResult;
CString strVolName, strVolMountPoint, strMountPointPath;
LPTSTR lpstr = strVolName.GetBuffer(MAX_PATH);
bResult = GetVolumeNameForVolumeMountPoint( strPath, lpstr, MAX_PATH );
strVolName.ReleaseBuffer();
if( !bResult )
return;
// Cut the final backslash of the volume name and search it in the volumes array
CString strVolName2 = strVolName.Left( strVolName.GetLength() - 1 );
for( int i = 0; i < arrVolumesData.GetSize(); i++ )
{
CItemData* pData = (CItemData*)(arrVolumesData[i]);
if( pData->GetVolumeName() == strVolName2 )
{
// Cut the final backslash of the path and add it to the volume's mount paths
CString strPath2 = strPath.Left( strPath.GetLength() - 1 );
pData->GetMountPaths().Add(strPath2);
}
}
lpstr = strVolMountPoint.GetBuffer(MAX_PATH);
HANDLE h = FindFirstVolumeMountPoint( strVolName, lpstr, MAX_PATH);
strVolMountPoint.ReleaseBuffer();
if( h == INVALID_HANDLE_VALUE )
return;
for( ; ; )
{
strMountPointPath = strPath + strVolMountPoint;
QueryMountListInPath( strMountPointPath, arrVolumesData );
lpstr = strVolMountPoint.GetBuffer(MAX_PATH);
bResult = FindNextVolumeMountPoint( h, lpstr, MAX_PATH );
strVolMountPoint.ReleaseBuffer();
if( !bResult )
break;
}
FindVolumeMountPointClose(h);
MY_CATCH_AND_THROW
}
/*
Global function: QueryMountList
Purpose: Query the mount manager for all mount paths of the given volumes
Each found mount path is added to the corresponding volume in array arrItems ( if any )
Parameters: [IN/OUT] CObArray& arrVolumesData
Array of CItemData - Tree items ( volumes ) whose mount paths we are looking for
Return value: -
*/
void QueryMountList( CObArray& arrVolumesData )
{
MY_TRY
CString strName = _T("X:\\");
for( TCHAR cDriveLetter = _T('A'); cDriveLetter <= _T('Z'); cDriveLetter++ )
{
strName.SetAt(0, cDriveLetter);
QueryMountListInPath( strName, arrVolumesData );
}
MY_CATCH_AND_THROW
}
/*
Global function: ConvertPartitionsToFT
Purpose: Scans an array of CItemData and converts all physical partitions to
FT partitions. Then return the logical volume ID's of all items in the array
Parameters: [IN] CObArray& arrVolumeData
The array of CItemData to scan
[OUT] FT_LOGICAL_DISK_ID* arrVolID
The array of logical volume ID's of all items from arrVolumeData
( arrVolID[i] is the logical volume ID of volume represented by arrVolumeData[i] )
Return value: TRUE if all physical partitions are converted succesfully
If one conversion fails then all previously converted partitions are deconverted
*/
BOOL ConvertPartitionsToFT( CObArray& arrVolumeData, FT_LOGICAL_DISK_ID* arrVolID )
{
MY_TRY
ASSERT( arrVolID );
for( int i = 0; i < arrVolumeData.GetSize(); i++ )
{
CItemData* pData = (CItemData*)(arrVolumeData[i]);
ASSERT(pData);
if( pData->GetItemType() == IT_LogicalVolume )
pData->GetVolumeID( arrVolID[i] );
else if( pData->GetItemType() == IT_PhysicalPartition )
{
ASSERT( !pData->GetVolumeName().IsEmpty() );
if( !FTPart( pData->GetVolumeName(),
pData->GetDriveLetter(),
&(arrVolID[i]) ) )
{
// Deconvert all partitions you've previously converted and return FALSE
DeconvertPartitionsFromFT( arrVolumeData, arrVolID, i );
return FALSE;
}
}
else
ASSERT(FALSE);
}
return TRUE;
MY_CATCH_AND_THROW
}
/*
Global function: DeconvertPartitionsFromFT
Purpose: Scans an array of CItemData and deconverts all physical partitions from
FT partitions.
Parameters: [IN] CObArray& arrVolumeData
The array of CItemData to scan
[IN] FT_LOGICAL_DISK_ID* arrVolID
The array of logical volume ID's of volumes from arrVolumeData
( arrVolID[i] is the logical volume ID of volume represented by arrVolumeData[i] )
[IN] int nItems
The number of items ( starting with offset zero ) to deconvert
If nItems = -1 then all items in the array will be scanned and deconverted
Return value: TRUE if all physical partitions are deconverted succesfully
*/
BOOL DeconvertPartitionsFromFT( CObArray& arrVolumeData, FT_LOGICAL_DISK_ID* arrVolID, int nItems /* =-1 */ )
{
MY_TRY
BOOL bResult = TRUE;
if( nItems == -1 )
nItems = (int)arrVolumeData.GetSize();
for( int i = 0; i < nItems; i++ )
{
CItemData* pData = (CItemData*)(arrVolumeData[i]);
ASSERT(pData);
if( pData->GetItemType() == IT_PhysicalPartition )
bResult = FTBreak( arrVolID[i] ) && bResult;
}
return bResult;
MY_CATCH_AND_THROW
}
/*
Global function: CheckAdministratorsMembership
Purpose: Checks whether the current user is a member of the Administrators' group
Parameters: [OUT] BOOL& bIsAdministrator
Returns TRUE if the user is a member of the administrators group
Return value: TRUE the check concluded successfully with a YES / NO answer
*/
BOOL CheckAdministratorsMembership( BOOL& bIsAdministrator )
{
MY_TRY
BYTE sidBuffer[100];
PSID pSID = (PSID)&sidBuffer;
SID_IDENTIFIER_AUTHORITY SIDAuth = SECURITY_NT_AUTHORITY;
// Create a SID for the BUILTIN\Administrators group.
if( !AllocateAndInitializeSid( &SIDAuth, 2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0,
&pSID) )
{
TRACE(_T("Error in AllocateAndInitializeSid\n"));
DisplaySystemErrorMessage( IDS_ERR_CHECK_ADMINISTRATOR );
return FALSE;
}
if( !CheckTokenMembership( NULL, pSID, &bIsAdministrator ) )
{
TRACE(_T("Error in CheckTokenMembership\n"));
DisplaySystemErrorMessage( IDS_ERR_CHECK_ADMINISTRATOR );
return FALSE;
}
if (pSID)
FreeSid(pSID);
return TRUE;
MY_CATCH_AND_THROW
}