#include <windows.h>
#include <stdio.h>
#define MAXPRINT 8192
static int Opt_verbose;
static int Opt_sparse;
static int Opt_force;
static void
out_err_vargs(const wchar_t *fmt, va_list ap)
{
wchar_t errmsg[MAXPRINT];
DWORD lasterr = GetLastError();
vfwprintf(stderr, fmt, ap);
if (lasterr) {
size_t size = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM,
NULL, lasterr,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
errmsg, MAXPRINT, NULL);
fwprintf(stderr, L": %s", errmsg);
} else {
fwprintf(stderr, L"\n");
}
SetLastError(0);
}
static void
out_err(const wchar_t *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
out_err_vargs(fmt, ap);
va_end(ap);
}
static void
print_file_size(const wchar_t *filename)
{
LARGE_INTEGER filesize;
FILE_COMPRESSION_INFO fci;
HANDLE fh = CreateFileW(filename, GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (fh == INVALID_HANDLE_VALUE) {
out_err(L"CreateFile");
return;
}
BOOL ret = GetFileSizeEx(fh, &filesize);
if (ret == FALSE) {
out_err(L"GetFileSizeEx");
goto err;
}
ret = GetFileInformationByHandleEx(fh, FileCompressionInfo,
&fci, sizeof(fci));
if (ret == FALSE) {
out_err(L"GetFileInformationByHandleEx");
goto err;
}
if (filesize.QuadPart < 65536)
fwprintf(stderr, L"\ntotal size: %lluB",
filesize.QuadPart);
else
fwprintf(stderr, L"\ntotal size: %lluKB",
filesize.QuadPart / 1024);
if (fci.CompressedFileSize.QuadPart < 65536)
fwprintf(stderr, L", actual size on disk: %lluKB\n",
fci.CompressedFileSize.QuadPart);
else
fwprintf(stderr, L", actual size on disk: %lluKB\n",
fci.CompressedFileSize.QuadPart / 1024);
err:
CloseHandle(fh);
}
static int
create_sparse_file(const wchar_t *filename, size_t len)
{
DWORD create = Opt_force ? CREATE_ALWAYS : CREATE_NEW;
HANDLE fh = CreateFileW(filename, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
create, FILE_ATTRIBUTE_NORMAL, NULL);
if (fh == INVALID_HANDLE_VALUE) {
out_err(L"CreateFile");
return -1;
}
SetLastError(0);
DWORD flags = 0;
BOOL ret = GetVolumeInformationByHandleW(fh, NULL, 0, NULL, NULL,
&flags, NULL, 0);
if (ret == FALSE) {
if (Opt_verbose || Opt_sparse)
out_err(L"GetVolumeInformationByHandle");
} else if ((flags & FILE_SUPPORTS_SPARSE_FILES) == 0) {
if (Opt_verbose || Opt_sparse)
out_err(L"Volume does not support sparse files.");
if (Opt_sparse)
goto err;
}
if (flags & FILE_SUPPORTS_SPARSE_FILES) {
DWORD nbytes;
ret = DeviceIoControl(fh, FSCTL_SET_SPARSE, NULL, 0, NULL,
0, &nbytes, NULL);
if (ret == FALSE) {
if (Opt_verbose || Opt_sparse)
out_err(L"DeviceIoControl");
if (Opt_sparse)
goto err;
}
}
LARGE_INTEGER llen;
llen.QuadPart = len;
DWORD ptr = SetFilePointerEx(fh, llen, NULL, FILE_BEGIN);
if (ptr == INVALID_SET_FILE_POINTER) {
out_err(L"SetFilePointerEx");
goto err;
}
ret = SetEndOfFile(fh);
if (ret == FALSE) {
out_err(L"SetEndOfFile");
goto err;
}
CloseHandle(fh);
return 0;
err:
CloseHandle(fh);
DeleteFileW(filename);
return -1;
}
int
wmain(int argc, const wchar_t *argv[])
{
if (argc < 2) {
fwprintf(stderr, L"Usage: %s filename len\n", argv[0]);
exit(1);
}
int i = 1;
while (i < argc && argv[i][0] == '-') {
switch (argv[i][1]) {
case 'v':
Opt_verbose = 1;
break;
case 's':
Opt_sparse = 1;
break;
case 'f':
Opt_force = 1;
break;
default:
out_err(L"Unknown option: \'%c\'.", argv[i][1]);
exit(2);
}
++i;
}
const wchar_t *filename = argv[i];
long long len = _wtoll(argv[i + 1]);
if (len < 0) {
out_err(L"Invalid file length: %lld.\n", len);
exit(3);
}
if (create_sparse_file(filename, len) < 0) {
out_err(L"File creation failed.");
exit(4);
}
if (Opt_verbose)
print_file_size(filename);
return 0;
}