/*** 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 #include "FS.hpp" #include "FSPlatformDevices.hpp" #if defined(AURORA_PLATFORM_WIN32) #include #include #include #include #include #else #include #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 AuROString &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 GetDeviceFromPath(const AuROString &path) { return GetDeviceFromRoot(GetRootFromPath(path)); } AUKN_SYM AuResult GetLogicalMountFromPath(const AuROString &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 (AuEndsWith(utf8Root, "\\")) { utf8Root.pop_back(); } return AuString(utf8Root); } AUKN_SYM AuResult GetDeviceFromRoot(const AuROString &root) { VOLUME_DISK_EXTENTS extents; DWORD dwBytesWritten {}; auto utf8Root = fmt::format("\\\\.\\{}", root); auto utf8Root2 = utf8Root; if (AuEndsWith(utf8Root, "\\")) { utf8Root.pop_back(); } auto widePath = Locale::ConvertFromUTF8(utf8Root); if (widePath.empty() && utf8Root.size()) { SysPushErrorMemory(); return {}; } 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...) return AuString(utf8Root); } auto hFile = Win32Open(widePath.c_str(), 0, FILE_SHARE_WRITE | FILE_SHARE_READ, false, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, FILE_ATTRIBUTE_NORMAL); 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) { return AuString(fmt::format("\\\\.\\PhysicalDrive{}", extents.Extents->DiskNumber)); } else { return {}; } } static AuUInt32 GetSectorSizeFromPathFromDevice(const AuROString &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; } auto hDevice = Win32Open(widePath.c_str(), 0, 0, false, OPEN_EXISTING); 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 AuROString &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 AuROString &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 AuROString &path) { return GetSectorSizeFromPathFromDevice(path, false); } AUKN_SYM LogicalUsedResponse GetLogicalUsedFromPath(const AuROString &path) { auto rootPath = GetLogicalMountFromPath(path); if (!rootPath) { return {}; } return GetLogicalUsedFromLogicalDevice(rootPath.GetResult()); } AUKN_SYM LogicalUsedResponse GetLogicalUsedFromLogicalDevice(const AuROString &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 AuROString &physicalDevicePath) { DISK_GEOMETRY_EX geo {}; DWORD cbBytesReturned; bool bSuccess {}; auto widePath = Locale::ConvertFromUTF8(physicalDevicePath); if (widePath.empty()) { SysPushErrorIO(); return 0; } auto hDevice = Win32Open(widePath.c_str(), 0, 0, false, OPEN_EXISTING); 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; using VolumeDatabase_t = AuList; static void CopyVolumes(FSDevice &device, const VolumeDatabaseEntry_t &entry); static bool DoSetupDiRecursion(LPCGUID pGuidInferface, PCWSTR pszEnumerator, AuList &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; } hDevice = Win32Open(pInterfaceDetailData->DevicePath, 0, 0x00000007, false, OPEN_EXISTING); 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; } } } if (AuCodepointsToLower(device.devicePath).find("ven_nvme") != AuString::npos) { device.bus = EFSBusType::eBusNVMePCIe; } 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'; } auto hVolume = Win32Open(strVolumePath.c_str(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE, false, OPEN_EXISTING); 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 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 GetMountpointsFromVolume(const AuString &volumeName) { DWORD dwCharCount { 4096 }; PWCHAR pNameIterator {}; BOOL bSuccess {}; AuList names; AuList 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 &netDrives) { AuList 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 EnumerateNetworkShares() { AuList netDrives; EnumerateNetworkShares({}, RESOURCE_REMEMBERED, RESOURCETYPE_DISK, RESOURCEUSAGE_ALL, RESOURCEDISPLAYTYPE_SHARE, netDrives); return netDrives; } static void EnumNetworkMounts(AuList &devices) { for (const auto &a : EnumerateNetworkShares()) { FSDevice *pDevice {}; AuArray 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 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 AuROString &deviceOrLogicalMountPath) { #if defined(AURORA_PLATFORM_WIN32) return ResolveObjSymLink(AuString(deviceOrLogicalMountPath)); #else return AuString(deviceOrLogicalMountPath); #endif } AuList SysGetFSDevices() { AU_LOCK_GLOBAL_GUARD(gFSDirMutex); AuList 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 {}; } }