Skip to content

Instantly share code, notes, and snippets.

@kainjow
Last active June 3, 2016 20:08
Show Gist options
  • Save kainjow/d9e63fbfe5d9206dfb03923b320b5cab to your computer and use it in GitHub Desktop.
Save kainjow/d9e63fbfe5d9206dfb03923b320b5cab to your computer and use it in GitHub Desktop.
MSVC file pointer doesn't increase when writing to device path
#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