2023-12-05 18:44:38 +00:00
/***
Copyright ( C ) 2023 Jamie Reece Wilson ( a / k / a " Reece " ) . All rights reserved .
File : FSPlatformDevices . NT . cpp
Date : 2023 - 08 - 11
Date : 2023 - 12 - 05
Author : Reece
* * */
# include <Source/RuntimeInternal.hpp>
# include "FS.hpp"
# include "FSPlatformDevices.hpp"
# if defined(AURORA_PLATFORM_WIN32)
# include <shlwapi.h>
# include <winioctl.h>
# include <setupapi.h>
# include <winternl.h>
# include <Ntddvol.h>
# else
# include <pathcch.h>
# endif
namespace Aurora : : IO : : FS
{
struct NetworkDrive
{
AuString comment ;
AuString mountpoint ;
AuString remoteOrigin ;
AuString hostname ;
} ;
static const auto kImScaredAndDisorientated { 4096u } ;
static const auto kBUsePerformantIoRecommendation { true } ; // false /*accurate for testing*/
static const auto kdUsePerformantIoRecommendationRequiresOrderOfMangitudeCoefficient { 1.f } ;
static AuString PathToMount ( const AuString & root ) ;
AUKN_SYM AuString GetRootFromPath ( const AuString & path )
{
auto widePath = Locale : : ConvertFromUTF8 ( NormalizePathRet ( path ) ) ;
# if defined(AURORA_PLATFORM_WIN32)
// PathStripToRoot is utterly worthless garbage that cannot parse network addresses
#if 0
// do not switch to PathCchStripToRoot!
// (wont remove support for Windows Vista/7!)
widePath . reserve ( 4096 * 3 ) ;
return PathStripToRootW ( widePath . data ( ) ) ? Locale : : ConvertFromWChar ( widePath . c_str ( ) ) : " " ;
# else
std : : wstring str2 ( 32u * 1024u + 10 , L ' \x00 ' ) ;
// i perfer this Kernel32 api (desktop-class only)
// update: i was right. you need the Win8 shell api thats in UWP for network paths to work properly
auto almostBestPath = : : GetVolumePathNameW ( widePath . c_str ( ) , str2 . data ( ) , str2 . size ( ) ) ?
Locale : : ConvertFromWChar ( str2 . c_str ( ) ) :
" " ;
return PathToMount ( almostBestPath ) ; /* expand root mountpoints to a network address, if possible*/
# endif
# else
return PathCchStripToRoot ( widePath . data ( ) , widePath . size ( ) ) ? Locale : : ConvertFromWChar ( widePath . c_str ( ) ) : " " ;
# endif
}
AUKN_SYM AuResult < AuString > GetDeviceFromPath ( const AuString & path )
{
return GetDeviceFromRoot ( GetRootFromPath ( path ) ) ;
}
AUKN_SYM AuResult < AuString > GetLogicalMountFromPath ( const AuString & fileOrDirPath )
{
auto root = GetRootFromPath ( fileOrDirPath ) ;
if ( AuStartsWith ( root , " \\ \\ " ) )
{
if ( ! AuStartsWith ( root , " \\ \\ . \\ " ) )
{
if ( root . find ( " GLOBAL? " ) = = root . npos )
{
return root ;
}
}
}
auto utf8Root = fmt : : format ( " \\ \\ . \\ {} " , root ) ;
auto utf8Root2 = utf8Root ;
if ( utf8Root . ends_with ( " \\ " ) )
{
utf8Root . pop_back ( ) ;
}
2024-04-20 01:29:49 +00:00
return AuString ( utf8Root ) ;
2023-12-05 18:44:38 +00:00
}
AUKN_SYM AuResult < AuString > GetDeviceFromRoot ( const AuString & root )
{
VOLUME_DISK_EXTENTS extents ;
DWORD dwBytesWritten { } ;
auto utf8Root = fmt : : format ( " \\ \\ . \\ {} " , root ) ;
auto utf8Root2 = utf8Root ;
if ( utf8Root . ends_with ( " \\ " ) )
{
utf8Root . pop_back ( ) ;
}
auto widePath = Locale : : ConvertFromUTF8 ( utf8Root ) ;
if ( : : GetDriveTypeW ( Locale : : ConvertFromUTF8 ( utf8Root2 ) . data ( ) ) ! = DRIVE_FIXED )
{
// Assume device is the same as the logical device
// This is generally true when the volume has no partitioning and only has one filesystem - think: CDs, network mounts, etc
// Only a subset of FIXED disks get a \\.\PhysicalDevice
// The path we currently have is usually good enough for whatever IOCTLs we need to send (the same cant be said for fixed disks tho)
// (they fail; they need the following...)
2024-04-20 01:29:49 +00:00
return AuString ( utf8Root ) ;
2023-12-05 18:44:38 +00:00
}
2024-04-09 22:39:00 +00:00
auto hFile = Win32Open ( widePath . c_str ( ) ,
0 ,
FILE_SHARE_WRITE | FILE_SHARE_READ ,
false ,
OPEN_EXISTING ,
2024-04-10 07:20:47 +00:00
FILE_FLAG_BACKUP_SEMANTICS ,
FILE_ATTRIBUTE_NORMAL ) ;
2023-12-05 18:44:38 +00:00
if ( hFile = = INVALID_HANDLE_VALUE )
{
SysPushErrorHAL ( " Couldn't find file device [1] {} " , GetLastError ( ) ) ;
return " " ;
}
if ( ! : : DeviceIoControl ( hFile ,
IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS ,
nullptr , 0 ,
& extents , sizeof ( extents ) ,
& dwBytesWritten ,
nullptr ) )
{
AuWin32CloseHandle ( hFile ) ;
if ( auto opt = GetFSDeviceByFilePath ( root ) )
{
auto copy = opt - > devicePath ;
return AuMove ( copy ) ;
}
else
{
return { } ;
}
}
AuWin32CloseHandle ( hFile ) ;
if ( extents . NumberOfDiskExtents )
{
2024-04-20 01:29:49 +00:00
return AuString ( fmt : : format ( " \\ \\ . \\ PhysicalDrive{} " , extents . Extents - > DiskNumber ) ) ;
2023-12-05 18:44:38 +00:00
}
else
{
return { } ;
}
}
static AuUInt32 GetSectorSizeFromPathFromDevice ( const AuString & path , bool bIsLogical )
{
DISK_GEOMETRY_EX geo { } ;
DWORD cbBytesReturned ;
bool bSuccess { } ;
auto rootPath = GetRootFromPath ( path ) ;
if ( rootPath . empty ( ) )
{
SysPushErrorIO ( ) ;
return kImScaredAndDisorientated ;
}
auto physPath = GetDeviceFromRoot ( rootPath ) ;
if ( ! physPath )
{
SysPushErrorIO ( ) ;
return kImScaredAndDisorientated ;
}
auto widePath = Locale : : ConvertFromUTF8 ( physPath . GetResult ( ) ) ;
if ( widePath . empty ( ) )
{
SysPushErrorIO ( ) ;
return kImScaredAndDisorientated ;
}
2024-04-09 22:39:00 +00:00
auto hDevice = Win32Open ( widePath . c_str ( ) ,
0 ,
0 ,
false ,
OPEN_EXISTING ) ;
2023-12-05 18:44:38 +00:00
if ( hDevice = = INVALID_HANDLE_VALUE )
{
SysPushErrorIO ( ) ;
AuWin32CloseHandle ( hDevice ) ;
return kImScaredAndDisorientated ;
}
bSuccess = : : DeviceIoControl ( hDevice ,
IOCTL_DISK_GET_DRIVE_GEOMETRY_EX ,
NULL , 0 ,
( LPVOID ) & geo , sizeof ( geo ) ,
& cbBytesReturned ,
nullptr ) ;
AuWin32CloseHandle ( hDevice ) ;
if ( bSuccess )
{
return geo . Geometry . BytesPerSector ;
}
else
{
return kImScaredAndDisorientated ;
}
}
AUKN_SYM AuUInt32 GetLogicalSectorSizeFromPath ( const AuString & path )
{
// TODO: ioctl BLKSSZGET under linux or GetPhysicalSectorSizeFromPath(path)
// Ports-Note: we cannot depend on FILE_STORAGE_INFO because that ioctl is dependent on Windows 8
// though, it is available under UWP. Might be useful
if ( auto dwBestGuessLogicalSize = GetSectorSizeFromPathFromDevice ( path , true ) )
{
return dwBestGuessLogicalSize ;
}
else
{
auto rootPath = GetRootFromPath ( path ) ;
auto widePath = Locale : : ConvertFromUTF8 ( rootPath ) ;
DWORD dwSectorsPerCluster ,
dwBytesPerSector ,
dwNumberOfFreeClusters ,
dwTotalNumberOfClusters ;
if ( : : GetDiskFreeSpaceW ( widePath . c_str ( ) ,
& dwSectorsPerCluster ,
& dwBytesPerSector ,
& dwNumberOfFreeClusters ,
& dwTotalNumberOfClusters ) )
{
return dwBytesPerSector *
dwSectorsPerCluster ; // this should equal `Bytes Per Cluster` under `fsutil fsinfo ntfsinfo C:`
}
else
{
return { } ;
}
}
}
AUKN_SYM AuUInt32 GetPerformanceBufferSizeFromPath ( const AuString & path )
{
if ( kBUsePerformantIoRecommendation )
{
return ( float ) GetPhysicalSectorSizeFromPath ( path ) * 2048.f // trust me bro. optimized for throughput and memory usage (requires 1-8MB)
// (based on crystal disk mark, nvme, real sata, spinning rust, and other real world values)
* ( float ) kdUsePerformantIoRecommendationRequiresOrderOfMangitudeCoefficient /* bruteforce dumb applications */ ;
}
else
{
// ...a more programmatic path. one cluster per queue, perhaps? well, that'll be our base recommendation for now.
auto rootPath = GetRootFromPath ( path ) ;
auto widePath = Locale : : ConvertFromUTF8 ( rootPath ) ;
DWORD dwSectorsPerCluster ,
dwBytesPerSector ,
dwNumberOfFreeClusters ,
dwTotalNumberOfClusters ;
if ( : : GetDiskFreeSpaceW ( widePath . c_str ( ) ,
& dwSectorsPerCluster ,
& dwBytesPerSector ,
& dwNumberOfFreeClusters ,
& dwTotalNumberOfClusters ) )
{
return dwBytesPerSector *
dwSectorsPerCluster ; // this should equal `Bytes Per Cluster` under `fsutil fsinfo ntfsinfo C:` (old windows) or `fsutil fsinfo sectorinfo C:` (new windows)
}
else
{
return GetPhysicalSectorSizeFromPath ( path ) ;
}
}
}
AUKN_SYM AuUInt32 GetPhysicalSectorSizeFromPath ( const AuString & path )
{
return GetSectorSizeFromPathFromDevice ( path , false ) ;
}
AUKN_SYM LogicalUsedResponse GetLogicalUsedFromPath ( const AuString & path )
{
auto rootPath = GetLogicalMountFromPath ( path ) ;
if ( ! rootPath )
{
return { } ;
}
return GetLogicalUsedFromLogicalDevice ( rootPath . GetResult ( ) ) ;
}
AUKN_SYM LogicalUsedResponse GetLogicalUsedFromLogicalDevice ( const AuString & logicalMountPath )
{
auto widePath = Locale : : ConvertFromUTF8 ( logicalMountPath ) ;
DWORD dwSectorsPerCluster ,
dwBytesPerSector ,
dwNumberOfFreeClusters ,
dwTotalNumberOfClusters ;
if ( : : GetDiskFreeSpaceW ( widePath . c_str ( ) ,
& dwSectorsPerCluster ,
& dwBytesPerSector ,
& dwNumberOfFreeClusters ,
& dwTotalNumberOfClusters ) )
{
AuUInt64 qwBytesPerCluster = AuUInt64 ( dwBytesPerSector ) * AuUInt64 ( dwSectorsPerCluster ) ;
AuUInt64 qwTotalBytes = qwBytesPerCluster * AuUInt64 ( dwTotalNumberOfClusters ) ;
AuUInt64 qwFreeBytes = qwBytesPerCluster * AuUInt64 ( dwNumberOfFreeClusters ) ;
AuUInt64 qwUsedBytes = qwTotalBytes - qwFreeBytes ;
return LogicalUsedResponse { qwTotalBytes , qwUsedBytes } ;
}
else
{
return { } ;
}
}
AUKN_SYM AuUInt64 GetDeviceSizeInBytes ( const AuString & physicalDevicePath )
{
DISK_GEOMETRY_EX geo { } ;
DWORD cbBytesReturned ;
bool bSuccess { } ;
auto widePath = Locale : : ConvertFromUTF8 ( physicalDevicePath ) ;
if ( widePath . empty ( ) )
{
SysPushErrorIO ( ) ;
return 0 ;
}
2024-04-09 22:39:00 +00:00
auto hDevice = Win32Open ( widePath . c_str ( ) ,
0 ,
0 ,
false ,
OPEN_EXISTING ) ;
2023-12-05 18:44:38 +00:00
if ( hDevice = = INVALID_HANDLE_VALUE )
{
SysPushErrorIO ( ) ;
AuWin32CloseHandle ( hDevice ) ;
return 0 ;
}
bSuccess = : : DeviceIoControl ( hDevice ,
IOCTL_DISK_GET_DRIVE_GEOMETRY_EX ,
NULL , 0 ,
( LPVOID ) & geo , sizeof ( geo ) ,
& cbBytesReturned ,
nullptr ) ;
AuWin32CloseHandle ( hDevice ) ;
if ( bSuccess )
{
return geo . DiskSize . QuadPart ;
}
else
{
SysPushErrorIO ( ) ;
return 0 ;
}
}
# if defined(AURORA_PLATFORM_WIN32)
struct VolumeExtendedDataInfo_t
{
} ;
using VolumeDatabaseEntry_t = AuTuple < AuString /*strVolumePath*/ , AuUInt32 /*uDiskNumberNumber*/ , AuUInt32 /*uPartitionNumber*/ , AuUInt32 /*uDevType*/ , AuUInt64 /*uSectionOffset*/ , AuUInt64 /*uSectionLength*/ , VolumeExtendedDataInfo_t > ;
using VolumeDatabase_t = AuList < VolumeDatabaseEntry_t > ;
static void CopyVolumes ( FSDevice & device , const VolumeDatabaseEntry_t & entry ) ;
static bool DoSetupDiRecursion ( LPCGUID pGuidInferface ,
PCWSTR pszEnumerator ,
AuList < FSDevice > & devices ,
VolumeDatabase_t & vols )
{
HDEVINFO hIntDevInfo { } ;
HANDLE hDevice = INVALID_HANDLE_VALUE ;
PSP_DEVICE_INTERFACE_DETAIL_DATA_W pInterfaceDetailData { } ;
if ( ! pSetupDiGetClassDevsW )
{
return { } ;
}
{
hIntDevInfo = pSetupDiGetClassDevsW ( pGuidInferface ,
pszEnumerator ,
NULL ,
pGuidInferface ? DIGCF_PRESENT | DIGCF_DEVICEINTERFACE : DIGCF_ALLCLASSES | DIGCF_PRESENT | DIGCF_DEVICEINTERFACE ) ;
if ( hIntDevInfo = = INVALID_HANDLE_VALUE )
{
return { } ;
}
for ( DWORD dwIndex = { } ;
;
dwIndex + + )
{
SP_DEVICE_INTERFACE_DATA interfaceData { } ;
SP_DEVINFO_DATA deviceInfoData { } ;
DWORD dwDataType , dwRequiredSize ;
BOOL bSuccess ;
FSDevice device ;
deviceInfoData . cbSize = sizeof ( deviceInfoData ) ;
interfaceData . cbSize = sizeof ( interfaceData ) ;
bSuccess = pSetupDiEnumDeviceInterfaces ( hIntDevInfo , NULL , pGuidInferface , dwIndex , & interfaceData ) ;
if ( ! bSuccess )
{
if ( GetLastError ( ) = = ERROR_NO_MORE_ITEMS )
{
break ;
}
SysPushErrorIO ( ) ;
break ;
}
dwRequiredSize = 0 ;
bSuccess = pSetupDiGetDeviceInterfaceDetailW ( hIntDevInfo , & interfaceData , NULL , 0 , & dwRequiredSize , NULL ) ;
if ( ( ! bSuccess & & GetLastError ( ) ! = ERROR_INSUFFICIENT_BUFFER ) | | dwRequiredSize = = 0 )
{
SysPushErrorIO ( ) ;
continue ;
}
if ( pInterfaceDetailData )
{
AuMemory : : Free ( pInterfaceDetailData ) ;
pInterfaceDetailData = nullptr ;
}
pInterfaceDetailData = ( PSP_DEVICE_INTERFACE_DETAIL_DATA_W ) AuMemory : : _ZAlloc ( dwRequiredSize ) ;
if ( ! pInterfaceDetailData )
{
SysPushErrorMemory ( ) ;
continue ;
}
pInterfaceDetailData - > cbSize = sizeof ( SP_DEVICE_INTERFACE_DETAIL_DATA ) ;
bSuccess = pSetupDiGetDeviceInterfaceDetailW ( hIntDevInfo , & interfaceData ,
pInterfaceDetailData , dwRequiredSize ,
& dwRequiredSize , & deviceInfoData ) ;
if ( ! bSuccess )
{
continue ;
}
2024-04-09 22:39:00 +00:00
hDevice = Win32Open ( pInterfaceDetailData - > DevicePath ,
0 ,
0x00000007 ,
false ,
OPEN_EXISTING ) ;
2023-12-05 18:44:38 +00:00
if ( hDevice ! = INVALID_HANDLE_VALUE )
{
STORAGE_DEVICE_NUMBER sdn { } ;
DISK_GEOMETRY_EX geo { } ;
DWORD cbBytesReturned ;
TCHAR szBuffer [ 4096 ] ;
device . devicePath = AuLocale : : ConvertFromWChar ( pInterfaceDetailData - > DevicePath ) ;
if ( device . devicePath . size ( ) & & device . devicePath [ device . devicePath . size ( ) - 1 ] = = ' } ' )
{
auto itr = device . devicePath . find_last_of ( " # " ) ;
if ( itr ! = AuString : : npos )
{
device . uuid = uuids : : uuid : : from_string ( device . devicePath . substr ( itr + 2 , 36 ) ) . value_or ( uuids : : uuid { } ) ;
}
}
bSuccess = : : DeviceIoControl ( hDevice ,
IOCTL_DISK_GET_DRIVE_GEOMETRY_EX ,
nullptr ,
0 ,
( LPVOID ) & geo , sizeof ( geo ) ,
& cbBytesReturned ,
nullptr ) ;
if ( bSuccess )
{
device . uFSDevicePageSizeInBytes = geo . Geometry . BytesPerSector ;
device . uFSDeviceSizeInBytes = geo . DiskSize . QuadPart ;
}
bSuccess = : : DeviceIoControl ( hDevice ,
IOCTL_STORAGE_GET_DEVICE_NUMBER ,
NULL , 0 ,
( LPVOID ) & sdn , sizeof ( sdn ) ,
& cbBytesReturned ,
nullptr ) ;
if ( bSuccess )
{
for ( const auto & volRef : vols )
{
if ( AuGet < 1 > ( volRef ) = = sdn . DeviceNumber & &
AuGet < 3 > ( volRef ) = = sdn . DeviceType )
{
CopyVolumes ( device , volRef ) ;
}
}
}
bSuccess = pSetupDiGetDeviceRegistryPropertyA ( hIntDevInfo , & deviceInfoData , SPDRP_CLASS , & dwDataType ,
( PBYTE ) szBuffer , sizeof ( szBuffer ) , & dwRequiredSize ) ;
if ( bSuccess )
{
device . bus = EFSBusType : : eBusGeneric ;
if ( strcmp ( " CDROM " , szBuffer ) = = 0 )
{
device . type = EFSDeviceType : : eDeviceCD ;
}
else if ( strcmp ( " DiskDrive " , szBuffer ) = = 0 )
{
device . type = EFSDeviceType : : eDeviceDisk ;
}
else if ( strcmp ( " USB " , szBuffer ) = = 0 )
{
device . type = EFSDeviceType : : eDeviceUSBMass ;
device . bus = EFSBusType : : eBusUSB ;
}
else
{
if ( pGuidInferface = = ( GUID * ) & GUID_DEVINTERFACE_DISK )
{
device . type = EFSDeviceType : : eDeviceDisk ;
}
else if ( pGuidInferface = = ( GUID * ) & GUID_DEVINTERFACE_FLOPPY )
{
device . type = EFSDeviceType : : eDeviceFloppy ;
}
else if ( pGuidInferface = = ( GUID * ) & GUID_DEVINTERFACE_CDROM )
{
device . type = EFSDeviceType : : eDeviceCD ;
}
else if ( pGuidInferface = = ( GUID * ) & GUID_DEVINTERFACE_VMLUN )
{
device . type = EFSDeviceType : : eDeviceSCSI ;
device . bus = EFSBusType : : eBusSCSI ;
}
}
}
bSuccess = pSetupDiGetDeviceRegistryPropertyA ( hIntDevInfo , & deviceInfoData , SPDRP_HARDWAREID , & dwDataType ,
( PBYTE ) szBuffer , sizeof ( szBuffer ) , & dwRequiredSize ) ;
bSuccess = pSetupDiGetDeviceRegistryPropertyA ( hIntDevInfo , & deviceInfoData , SPDRP_FRIENDLYNAME , & dwDataType ,
( PBYTE ) szBuffer , sizeof ( szBuffer ) , & dwRequiredSize ) ;
if ( bSuccess )
{
device . productModel = szBuffer ;
}
bSuccess = pSetupDiGetDeviceRegistryPropertyA ( hIntDevInfo , & deviceInfoData , SPDRP_DEVICEDESC , & dwDataType ,
( PBYTE ) szBuffer , sizeof ( szBuffer ) , & dwRequiredSize ) ;
if ( bSuccess )
{
device . altProductDescription = szBuffer ;
}
if ( ! device . uFSDevicePageSizeInBytes )
{
device . uFSDevicePageSizeInBytes = kImScaredAndDisorientated ;
}
devices . push_back ( device ) ;
}
: : CloseHandle ( hDevice ) ;
hDevice = INVALID_HANDLE_VALUE ;
}
}
{
if ( pInterfaceDetailData )
{
AuMemory : : Free ( pInterfaceDetailData ) ;
}
if ( hDevice ! = INVALID_HANDLE_VALUE )
{
: : CloseHandle ( hDevice ) ;
}
if ( hIntDevInfo )
{
pSetupDiDestroyDeviceInfoList ( hIntDevInfo ) ;
}
}
return true ;
}
static AuString ResolveObjSymLink ( const AuString & reeceWasHere )
{
OBJECT_ATTRIBUTES objectAttributes ;
ULONG uReturnedLength { } ;
NTSTATUS uStatus ;
HANDLE hHandle ;
if ( ! pNtOpenSymbolicLinkObject )
{
return reeceWasHere ;
}
auto path = reeceWasHere ;
AuReplaceAll ( path , " \\ \\ ? " , " \\ GLOBAL?? " ) ;
auto widePath = Locale : : ConvertFromUTF8 ( path ) ;
UNICODE_STRING targetDevice ;
targetDevice . Buffer = widePath . data ( ) ;
targetDevice . Length = ( USHORT ) widePath . size ( ) * 2 ;
InitializeObjectAttributes ( & objectAttributes , & targetDevice , OBJ_CASE_INSENSITIVE , NULL , NULL ) ;
uStatus = pNtOpenSymbolicLinkObject ( & hHandle , 1 , & objectAttributes ) ;
if ( uStatus ! = 0 )
{
return reeceWasHere ;
}
if ( hHandle = = INVALID_HANDLE_VALUE )
{
return reeceWasHere ;
}
std : : wstring buffer ( 32 * 1024 , L ' \00 ' ) ;
UNICODE_STRING linkTarget ;
linkTarget . Buffer = buffer . data ( ) ;
linkTarget . Length = linkTarget . MaximumLength = ( USHORT ) buffer . size ( ) ; // meh, any big buffer will do. if it's too big, it wont work.
uStatus = pNtQuerySymbolicLinkObject ( hHandle , & linkTarget , & uReturnedLength ) ;
if ( uStatus ! = 0 )
{
AuWin32CloseHandle ( hHandle ) ;
return path ;
}
if ( uReturnedLength = = 0 )
{
AuWin32CloseHandle ( hHandle ) ;
AU_THROW_CONST_STRING ( " TrySimplifyDevicePath() failed. " ) ;
}
buffer . resize ( uReturnedLength ) ;
path = AuLocale : : ConvertFromWChar ( buffer . c_str ( ) ) ;
AuWin32CloseHandle ( hHandle ) ;
return path ;
}
bool DoLameAndSlowVolIteration ( VolumeDatabase_t & database )
{
std : : wstring strVolumePath ;
strVolumePath . resize ( 16 * 1024 ) ;
auto hVolume = : : FindFirstVolumeW ( strVolumePath . data ( ) , strVolumePath . size ( ) ) ;
if ( hVolume = = INVALID_HANDLE_VALUE )
{
return false ;
}
do
{
{
int i = wcslen ( strVolumePath . c_str ( ) ) ;
if ( ! i )
{
i = 1 ;
}
strVolumePath [ i - 1 ] = ' \x00 ' ;
}
2024-04-09 22:39:00 +00:00
auto hVolume = Win32Open ( strVolumePath . c_str ( ) ,
0 ,
FILE_SHARE_READ | FILE_SHARE_WRITE ,
false ,
OPEN_EXISTING ) ;
2023-12-05 18:44:38 +00:00
if ( hVolume = = INVALID_HANDLE_VALUE )
{
continue ;
}
static constexpr AuUInt kBRet = sizeof ( VOLUME_DISK_EXTENTS ) + 256 * sizeof ( DISK_EXTENT ) ;
char tempVolumeDiskExtents [ kBRet ] ;
typedef struct _VOLUME_DISK_EXTENTS
{
DWORD NumberOfDiskExtents ;
DISK_EXTENT Extents [ ANYSIZE_ARRAY ] ;
} VOLUME_DISK_EXTENTS , * PVOLUME_DISK_EXTENTS ;
PVOLUME_DISK_EXTENTS pVde = ( PVOLUME_DISK_EXTENTS ) tempVolumeDiskExtents ;
DWORD dwBytesReturned { } ;
STORAGE_DEVICE_NUMBER sdn { } ;
auto bSuccess = : : DeviceIoControl ( hVolume ,
IOCTL_STORAGE_GET_DEVICE_NUMBER ,
NULL , 0 ,
( LPVOID ) & sdn , sizeof ( sdn ) ,
& dwBytesReturned ,
nullptr ) ;
if ( ! bSuccess )
{
AuResetMember ( sdn ) ;
}
if ( : : DeviceIoControl ( hVolume , IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS , NULL , 0 , ( void * ) pVde , AuSizeOf ( tempVolumeDiskExtents ) , & dwBytesReturned , NULL ) )
{
for ( AU_ITERATE_N ( i , pVde - > NumberOfDiskExtents ) )
{
const auto & refExtent = pVde - > Extents [ i ] ;
database . push_back ( { AuLocale : : ConvertFromWChar ( strVolumePath . c_str ( ) /*intentionally lose the length.*/ ) ,
( AuUInt32 ) refExtent . DiskNumber ,
( AuUInt32 ) sdn . PartitionNumber ,
( AuUInt32 ) sdn . DeviceType ,
( AuUInt64 ) refExtent . StartingOffset . QuadPart ,
( AuUInt64 ) refExtent . ExtentLength . QuadPart ,
{ } } ) ;
}
}
AuWin32CloseHandle ( hVolume ) ;
}
while ( : : FindNextVolumeW ( hVolume , strVolumePath . data ( ) , strVolumePath . size ( ) ) ! = 0 ) ;
: : FindVolumeClose ( hVolume ) ;
return true ;
}
static AuString PathToMount ( const AuString & root )
{
auto widePath = Locale : : ConvertFromUTF8 ( root ) ;
if ( : : GetDriveTypeW ( widePath . c_str ( ) ) = = DRIVE_REMOTE )
{
char temp [ 32 * 1024 * 3 ] ;
DWORD tempLength = sizeof ( temp ) ;
if ( pWNetGetUniversalNameW & &
pWNetGetUniversalNameW ( widePath . c_str ( ) , REMOTE_NAME_INFO_LEVEL , temp , & tempLength ) = = NO_ERROR )
{
auto pDescriptionOfDrive = ( LPREMOTE_NAME_INFOW ) temp ;
return AuLocale : : ConvertFromWChar ( pDescriptionOfDrive - > lpUniversalName ) ;
}
else
{
return root ;
}
}
else
{
// anyone else? NTFS mountpoints? tbd
return root ;
}
}
static AuOptional < AuString > GetBestVolLabel ( const AuString & volumeName )
{
auto widePath = Locale : : ConvertFromUTF8 ( volumeName ) ;
wchar_t buffer [ 4096 ] { } ;
DWORD dwBufferSize { AuArraySize ( buffer ) } ;
if ( ! GetVolumeInformationW ( widePath . c_str ( ) , buffer , dwBufferSize , { } , { } , { } , { } , { } ) )
{
return { } ;
}
return AuLocale : : ConvertFromWChar ( buffer ) ;
}
static AuList < AuString > GetMountpointsFromVolume ( const AuString & volumeName )
{
DWORD dwCharCount { 4096 } ;
PWCHAR pNameIterator { } ;
BOOL bSuccess { } ;
AuList < wchar_t > names ;
AuList < AuString > ret ;
auto widePath = Locale : : ConvertFromUTF8 ( volumeName ) ;
while ( true )
{
names . clear ( ) ;
names . resize ( dwCharCount ) ;
if ( ( bSuccess = GetVolumePathNamesForVolumeNameW ( widePath . c_str ( ) , names . data ( ) , dwCharCount , & dwCharCount ) ) )
{
pNameIterator = names . data ( ) ;
break ;
}
if ( GetLastError ( ) ! = ERROR_MORE_DATA )
{
break ;
}
}
if ( ! bSuccess )
{
return { } ;
}
for ( pNameIterator = names . data ( ) ;
pNameIterator [ 0 ] ! = L ' \0 ' ;
pNameIterator + = wcslen ( pNameIterator ) + 1 )
{
ret . push_back ( AuLocale : : ConvertFromWChar ( pNameIterator ) ) ;
}
return ret ;
}
static void CopyVolumes ( FSDevice & device , const VolumeDatabaseEntry_t & entry )
{
FSLogicalPartition partition ;
const auto & [ strVolumePath , uDiskNumberNumber , uPartitionNumber , uDevType , uSectionOffset , uSectionLength , ex ] = entry ;
partition . devicePath = device . devicePath ;
partition . logicalMount = strVolumePath + " \\ " ;
partition . filesystemMountPoints = GetMountpointsFromVolume ( partition . logicalMount ) ;
partition . offset . uLogicalSize = uSectionLength ;
partition . offset . uLogicalOffset = uSectionOffset ;
if ( partition . logicalMount . empty ( ) )
{
partition . logicalMount = partition . devicePath ;
}
if ( ! partition . filesystemMountPoints . empty ( ) )
{
partition . space = GetLogicalUsedFromLogicalDevice ( partition . filesystemMountPoints [ 0 ] ) ;
}
if ( AuStartsWith ( strVolumePath , " \\ \\ ? \\ Volume{ " ) )
{
partition . uuid = uuids : : uuid : : from_string ( strVolumePath . substr ( 11 , strVolumePath . size ( ) - 11 - 1 ) ) . value_or ( uuids : : uuid { } ) ;
}
partition . name = GetBestVolLabel ( partition . logicalMount ) ;
device . partitions . push_back ( partition ) ;
}
static void ReadExtendedVolumeInfo ( VolumeDatabase_t & vols )
{
}
static void EnumerateNetworkShares ( NETRESOURCEW * pRsrc ,
DWORD scope ,
DWORD type ,
DWORD usage ,
DWORD displayType ,
AuList < NetworkDrive > & netDrives )
{
AuList < char > buffer ( 512 * 1024 ) ;
DWORD dwBufferSize = buffer . size ( ) ;
HANDLE hHandle { } ;
DWORD dwResult { } ;
DWORD dwEntries { ( DWORD ) - 1 } ;
if ( ! pWNetOpenEnumW )
{
return ;
}
if ( pWNetOpenEnumW ( scope , type , usage , pRsrc , & hHandle ) ! = NO_ERROR )
{
return ;
}
do
{
dwResult = pWNetEnumResourceW ( hHandle , & dwEntries , buffer . data ( ) , & dwBufferSize ) ;
if ( dwResult = = NO_ERROR )
{
auto pNetResources = ( NETRESOURCEW * ) buffer . data ( ) ;
for ( AU_ITERATE_N ( i , dwEntries ) )
{
auto pRsrc = & pNetResources [ i ] ;
if ( pRsrc - > dwDisplayType = = displayType )
{
NetworkDrive drive ;
if ( pRsrc - > lpRemoteName )
{
drive . remoteOrigin = AuLocale : : ConvertFromWChar ( pRsrc - > lpRemoteName ) + " \\ " ;
if ( AuStartsWith ( drive . remoteOrigin , " \\ \\ " ) )
{
auto itr = drive . remoteOrigin . find ( ' \\ ' , 2 ) ;
if ( itr ! = drive . remoteOrigin . npos )
{
drive . hostname = drive . remoteOrigin . substr ( 2 , itr - 2 ) ;
}
}
}
if ( pRsrc - > lpLocalName )
{
drive . mountpoint = AuLocale : : ConvertFromWChar ( pRsrc - > lpLocalName ) + " \\ " ;
}
if ( pRsrc - > lpComment )
{
drive . comment = AuLocale : : ConvertFromWChar ( pRsrc - > lpComment ) ;
}
netDrives . push_back ( drive ) ;
}
if ( pRsrc - > dwUsage & RESOURCEUSAGE_CONTAINER )
{
EnumerateNetworkShares ( pRsrc , scope , type , usage , displayType , netDrives ) ;
}
}
}
else
{
break ;
}
}
while ( dwResult = = NO_ERROR & &
dwEntries ) ;
pWNetCloseEnum ( hHandle ) ;
}
static AuList < NetworkDrive > EnumerateNetworkShares ( )
{
AuList < NetworkDrive > netDrives ;
EnumerateNetworkShares ( { } , RESOURCE_REMEMBERED , RESOURCETYPE_DISK , RESOURCEUSAGE_ALL , RESOURCEDISPLAYTYPE_SHARE , netDrives ) ;
return netDrives ;
}
static void EnumNetworkMounts ( AuList < FSDevice > & devices )
{
for ( const auto & a : EnumerateNetworkShares ( ) )
{
FSDevice * pDevice { } ;
AuArray < AuUInt8 , 16 > hash ;
AuHashing : : MD4 ( a . hostname , hash ) ;
hash [ 8 ] & = 0xBF ;
hash [ 8 ] | = 0x80 ;
hash [ 6 ] & = 0x4F ;
hash [ 6 ] | = 0x40 ;
uuids : : uuid uid ( hash . begin ( ) , hash . end ( ) ) ;
for ( auto & dev : devices )
{
if ( dev . uuid = = uid & &
dev . bus = = EFSBusType : : eBusNetwork )
{
pDevice = & dev ;
break ;
}
}
if ( ! pDevice )
{
devices . push_back ( FSDevice { } ) ;
pDevice = & devices [ devices . size ( ) - 1 ] ;
}
pDevice - > uuid = uid ;
pDevice - > bus = EFSBusType : : eBusNetwork ;
pDevice - > type = EFSDeviceType : : eDeviceNetworkMount ;
pDevice - > altLabel = a . comment . size ( ) ? a . comment : " Network Drive " ;
pDevice - > altProductDescription = fmt : : format ( " Server ({}) " , a . hostname ) ;
pDevice - > devicePath = a . hostname ;
pDevice - > uFSDevicePageSizeInBytes = 4096 ;
{
FSLogicalPartition partition ;
AuArray < AuUInt8 , 16 > hash ;
AuHashing : : MD4 ( a . remoteOrigin , hash ) ;
hash [ 8 ] & = 0xBF ;
hash [ 8 ] | = 0x80 ;
hash [ 6 ] & = 0x4F ;
hash [ 6 ] | = 0x40 ;
partition . uuid = uuids : : uuid ( hash . begin ( ) , hash . end ( ) ) ;
partition . filesystemMountPoints = { a . mountpoint } ;
partition . logicalMount = a . remoteOrigin ;
partition . space = GetLogicalUsedFromLogicalDevice ( a . mountpoint ) ;
partition . offset = { partition . space . uLogicalSize , 0 } ;
partition . name = GetBestVolLabel ( a . mountpoint ) ;
partition . devicePath = pDevice - > devicePath ;
pDevice - > partitions . push_back ( partition ) ;
pDevice - > uFSDeviceSizeInBytes + = partition . space . uLogicalSize ;
}
}
}
# endif
AUKN_SYM AuString TrySimplifyDevicePath ( const AuString & deviceOrLogicalMountPath )
{
# if defined(AURORA_PLATFORM_WIN32)
return ResolveObjSymLink ( deviceOrLogicalMountPath ) ;
# else
return deviceOrLogicalMountPath ;
# endif
}
AuList < FSDevice > SysGetFSDevices ( )
{
AU_LOCK_GUARD ( gFSDirMutex ) ;
AuList < FSDevice > devices ;
# if defined(AURORA_PLATFORM_WIN32)
VolumeDatabase_t vols ;
( void ) DoLameAndSlowVolIteration ( vols ) ;
ReadExtendedVolumeInfo ( vols ) ;
DoSetupDiRecursion ( ( GUID * ) & GUID_DEVINTERFACE_DISK , { } , devices , vols ) ;
DoSetupDiRecursion ( ( GUID * ) & GUID_DEVINTERFACE_VMLUN , { } , devices , vols ) ;
DoSetupDiRecursion ( ( GUID * ) & GUID_DEVINTERFACE_CDROM , { } , devices , vols ) ;
DoSetupDiRecursion ( ( GUID * ) & GUID_DEVINTERFACE_FLOPPY , { } , devices , vols ) ;
DoSetupDiRecursion ( ( GUID * ) & GUID_DEVINTERFACE_PARTITION , { } , devices , vols ) ;
EnumNetworkMounts ( devices ) ;
return devices ;
# endif
return { } ;
}
}