Created
April 27, 2017 07:23
-
-
Save DrPizza/f9f4e553d7d0fba19d9de0f2cc84c26a to your computer and use it in GitHub Desktop.
This file contains 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 <SDKDDKVer.h> | |
#pragma warning(disable: 4710) // warning C4710: '%s': function not inlined | |
#pragma warning(disable: 4668) // warning C4668: '%s' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' | |
#pragma warning(disable: 4820) // warning C4820: '%s': '%d' bytes padding added after data member '%s' | |
#define STRICT | |
#define NOMINMAX | |
#include <Windows.h> | |
#if !defined(_STL_EXTRA_DISABLED_WARNINGS) | |
#define _STL_EXTRA_DISABLED_WARNINGS 4061 4365 4571 4623 4625 4626 4710 4774 4820 4987 5026 5027 | |
#endif | |
#include <vector> | |
#include <memory> | |
#include <iostream> | |
#include <locale> | |
#include <codecvt> | |
DWORD get_sector_size(const std::wstring& path) { | |
DWORD sectors_per_cluster = 0ul; | |
DWORD bytes_per_sector = 0ul; | |
DWORD free_clusters = 0ul; | |
DWORD total_clusters = 0ul; | |
::GetDiskFreeSpaceW(path.c_str(), §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters); | |
return bytes_per_sector; | |
} | |
unsigned __int64 align_down(unsigned __int64 value, unsigned __int64 alignment) { | |
if(alignment == 0 || 0 != (alignment & (alignment - 1))) { | |
return value; | |
} | |
return value & ~(alignment - 1ui64); | |
} | |
template<typename T> | |
T greatest_common_divisor(T a, T b) { | |
if(a == 0) { | |
return b; | |
} | |
if(b == 0) { | |
return a; | |
} | |
T shift = 0; | |
for(; 0 == ((a | b) & 1); ++shift) { | |
a >>= 1; | |
b >>= 1; | |
} | |
while(0 == (a & 1)) { | |
a >>= 1; | |
} | |
do { | |
while(0 == (b & 1)) { | |
b >>= 1; | |
} | |
if(a > b) { | |
std::swap(a, b); | |
} | |
b -= a; | |
} while(b != 0); | |
return a << shift; | |
} | |
template<typename T> | |
T least_common_multiple(T a, T b) { | |
return (a * b) / greatest_common_divisor(a, b); | |
} | |
int main(int argc, char* argv[]) | |
{ | |
std::wstring drive = std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>>{}.from_bytes(argc == 2 ? argv[1] : "C:\\"); | |
ULARGE_INTEGER free_bytes = { 0 }; | |
::GetDiskFreeSpaceExW(drive.c_str(), &free_bytes, nullptr, nullptr); | |
std::wstring path = drive + L"space_filler"; | |
HANDLE space_filler = ::CreateFileW(path.c_str(), GENERIC_ALL, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING | FILE_FLAG_DELETE_ON_CLOSE, nullptr); | |
DWORD sector_size = get_sector_size(drive); | |
constexpr size_t buffer_size = 1024 * 1024; | |
free_bytes.QuadPart = align_down(free_bytes.QuadPart, least_common_multiple(static_cast<size_t>(sector_size), buffer_size)); | |
LARGE_INTEGER distance = { 0 }; | |
distance.QuadPart = static_cast<__int64>(free_bytes.QuadPart); | |
::SetFilePointerEx(space_filler, distance, nullptr, FILE_BEGIN); | |
::SetEndOfFile(space_filler); | |
LARGE_INTEGER zero = { 0 }; | |
::SetFilePointerEx(space_filler, zero, nullptr, FILE_BEGIN); | |
std::unique_ptr<unsigned char[]> even_buffer{ new unsigned char[buffer_size] }; | |
std::unique_ptr<unsigned char[]> odd_buffer{ new unsigned char[buffer_size] }; | |
for(size_t i = 0; i < buffer_size; ++i) { | |
even_buffer[i] = static_cast<unsigned char>( i & 0xff ); | |
odd_buffer [i] = static_cast<unsigned char>(~(i & 0xff)); | |
} | |
std::unique_ptr<unsigned char[]> read_buffer{ new unsigned char[buffer_size] }; | |
const size_t blocks_to_write = free_bytes.QuadPart / buffer_size; | |
for(size_t iterations = 0; ; ++iterations) { | |
unsigned char* buffer = (iterations % 2) ? odd_buffer.get() : even_buffer.get(); | |
for(size_t i = 0; i < blocks_to_write; ++i) { | |
DWORD bytes_written = 0ul; | |
::WriteFile(space_filler, buffer, buffer_size, &bytes_written, nullptr); | |
} | |
::SetFilePointerEx(space_filler, zero, nullptr, FILE_BEGIN); | |
for(size_t i = 0; i < blocks_to_write; ++i) { | |
DWORD bytes_read = 0ul; | |
::ReadFile(space_filler, read_buffer.get(), buffer_size, &bytes_read, nullptr); | |
if(0 != std::memcmp(read_buffer.get(), buffer, buffer_size)) { | |
std::cout << "read error detected" << std::endl; | |
} | |
} | |
::SetFilePointerEx(space_filler, zero, nullptr, FILE_BEGIN); | |
std::cout << "Written " << (iterations + 1) * (blocks_to_write * buffer_size) << std::endl; | |
} | |
::CloseHandle(space_filler); | |
return 0; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment