Last active
June 3, 2016 20:08
-
-
Save kainjow/d9e63fbfe5d9206dfb03923b320b5cab to your computer and use it in GitHub Desktop.
MSVC file pointer doesn't increase when writing to device path
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <io.h> | |
#include <fcntl.h> | |
#include <stdlib.h> | |
#include <windows.h> | |
#include <iostream> | |
#include <string> | |
#include <vector> | |
#include <setupapi.h> | |
#include <sys/stat.h> | |
#pragma comment(lib, "setupapi") | |
class Disk { | |
public: | |
std::string devicePath; | |
std::string physicalDrivePath; | |
long long size; | |
int num; | |
Disk() : size(0), num(0) {} | |
}; | |
bool makeDisk(const char *devicePath, Disk& disk) | |
{ | |
// Open the device | |
HANDLE handle = CreateFileA(devicePath, 0, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); | |
if (handle == INVALID_HANDLE_VALUE) { | |
wprintf(L"Can't open device: %ld\n", GetLastError()); | |
return false; | |
} | |
// Generate the device path | |
STORAGE_DEVICE_NUMBER devNum; | |
DWORD bytesReturned = 0; | |
if (!DeviceIoControl(handle, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, &devNum, sizeof(devNum), &bytesReturned, NULL)) { | |
wprintf(L"Can't get device number: %ld\n", GetLastError()); | |
(void)CloseHandle(handle); | |
return false; | |
} | |
// Get the drive size | |
DISK_GEOMETRY_EX diskGeometry; | |
if (!DeviceIoControl(handle, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, NULL, 0, &diskGeometry, sizeof(diskGeometry), &bytesReturned, NULL)) { | |
wprintf(L"Can't get device geometry: %ld\n", GetLastError()); | |
(void)CloseHandle(handle); | |
return false; | |
} | |
(void)CloseHandle(handle); | |
disk.devicePath = devicePath; | |
disk.physicalDrivePath = "\\\\.\\PhysicalDrive" + std::to_string(devNum.DeviceNumber); | |
disk.size = diskGeometry.DiskSize.QuadPart; | |
disk.num = devNum.DeviceNumber; | |
return true; | |
} | |
std::vector<Disk> getDisks() | |
{ | |
std::vector<Disk> disks; | |
const GUID guid = GUID_DEVINTERFACE_DISK; | |
HDEVINFO devInfo = SetupDiGetClassDevsA(&guid, NULL, NULL, DIGCF_PRESENT | DIGCF_PROFILE | DIGCF_INTERFACEDEVICE); | |
if (devInfo != INVALID_HANDLE_VALUE) { | |
DWORD devInfoDataMemberIndex = 0; | |
SP_DEVINFO_DATA devInfoData; | |
devInfoData.cbSize = sizeof(devInfoData); | |
while (SetupDiEnumDeviceInfo(devInfo, devInfoDataMemberIndex, &devInfoData) == TRUE) { | |
DWORD devInterfaceDataMemberIndex = 0; | |
SP_DEVICE_INTERFACE_DATA devInterfaceData; | |
devInterfaceData.cbSize = sizeof(devInterfaceData); | |
while (SetupDiEnumDeviceInterfaces(devInfo, &devInfoData, &guid, devInterfaceDataMemberIndex, &devInterfaceData) == TRUE) { | |
DWORD requiredSize = 0; | |
if (SetupDiGetDeviceInterfaceDetailA(devInfo, &devInterfaceData, NULL, 0, &requiredSize, NULL) == FALSE && GetLastError() == ERROR_INSUFFICIENT_BUFFER) { | |
SP_DEVICE_INTERFACE_DETAIL_DATA_A *devInterfaceDetailData = (SP_DEVICE_INTERFACE_DETAIL_DATA_A*)malloc(requiredSize); | |
devInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A); // Must be size of the base struct, *not* requiredSize! | |
if (SetupDiGetDeviceInterfaceDetailA(devInfo, &devInterfaceData, devInterfaceDetailData, requiredSize, NULL, &devInfoData) == TRUE) { | |
Disk disk; | |
if (makeDisk(devInterfaceDetailData->DevicePath, disk)) { | |
disks.push_back(disk); | |
} | |
} | |
free(devInterfaceDetailData); | |
} | |
devInterfaceDataMemberIndex++; | |
} | |
devInfoDataMemberIndex++; | |
} | |
(void)SetupDiDestroyDeviceInfoList(devInfo); | |
} | |
return disks; | |
} | |
bool testWrite(const char *path, int which) | |
{ | |
long long initialFilePosition = -1; | |
long long finalFilePosition = -1; | |
char buf[512]; | |
memset(buf, 0, sizeof(buf)); | |
if (which == 0) { | |
printf("Testing stdio: %s\n", path); | |
int fd = -1; | |
errno_t err = _sopen_s(&fd, path, _O_WRONLY | _O_BINARY, _SH_DENYRW, _S_IWRITE); | |
if (err != 0) { | |
printf(" ERROR: open failed: %d\n", err); | |
return false; | |
} | |
initialFilePosition = _tell(fd); | |
int bytesWritten = _write(fd, buf, sizeof(buf)); | |
if (bytesWritten != sizeof(buf)) { | |
printf(" ERROR: %d bytes written: %d\n", bytesWritten, errno); | |
(void)_close(fd); | |
return false; | |
} | |
finalFilePosition = _tell(fd); | |
(void)_close(fd); | |
} | |
else { | |
printf("Testing win32: %s\n", path); | |
HANDLE h = CreateFileA(path, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); | |
if (h == INVALID_HANDLE_VALUE) { | |
printf(" ERROR: CreateFile failed: %ld\n", GetLastError()); | |
return false; | |
} | |
LARGE_INTEGER distanceToMove; | |
distanceToMove.QuadPart = 0; | |
LARGE_INTEGER pos1, pos2; | |
memset(&pos1, 0, sizeof(pos1)); | |
memset(&pos2, 0, sizeof(pos2)); | |
if (!SetFilePointerEx(h, distanceToMove, &pos1, FILE_CURRENT)) { | |
printf(" ERROR: Can't get file pointer: %ld\n", GetLastError()); | |
(void)CloseHandle(h); | |
return false; | |
} | |
initialFilePosition = pos1.QuadPart; | |
DWORD bytesWritten = 0; | |
if (!WriteFile(h, buf, sizeof(buf), &bytesWritten, NULL) || bytesWritten != sizeof(buf)) { | |
printf(" ERROR: WriteFile failed: %ld\n", GetLastError()); | |
(void)CloseHandle(h); | |
return false; | |
} | |
if (!SetFilePointerEx(h, distanceToMove, &pos2, FILE_CURRENT)) { | |
printf(" ERROR: Can't get file pointer: %ld\n", GetLastError()); | |
(void)CloseHandle(h); | |
return false; | |
} | |
finalFilePosition = pos2.QuadPart; | |
(void)CloseHandle(h); | |
} | |
if (finalFilePosition == initialFilePosition + (long long)sizeof(buf)) { | |
printf(" SUCCESS\n"); | |
} | |
else { | |
printf(" ERROR: file position did not change from %lld\n", initialFilePosition); | |
} | |
return true; | |
} | |
void go() { | |
std::vector<Disk> disks = getDisks(); | |
for (size_t i = 0; i < disks.size(); ++i) { | |
Disk& disk = disks.at(i); | |
printf("[%d]\n %s\n %s\n %lld bytes\n\n", | |
disk.num, | |
disk.devicePath.c_str(), | |
disk.physicalDrivePath.c_str(), | |
disk.size); | |
} | |
std::cout << "Enter disk number to test: " << std::endl; | |
int num = -1; | |
std::cin >> num; | |
for (size_t i = 0; i < disks.size(); ++i) { | |
Disk& disk = disks.at(i); | |
if (disk.num == num) { | |
if (!testWrite(disk.physicalDrivePath.c_str(), 0)) { | |
break; | |
} | |
if (!testWrite(disk.physicalDrivePath.c_str(), 1)) { | |
break; | |
} | |
if (!testWrite(disk.devicePath.c_str(), 0)) { | |
break; | |
} | |
if (!testWrite(disk.devicePath.c_str(), 1)) { | |
break; | |
} | |
break; | |
} | |
} | |
} | |
int main() | |
{ | |
go(); | |
system("pause"); | |
return 0; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment