public static void CreateSparse(string filename, long length)
{
if (!SupportsSparse)
return;
// Ensure we have the full path
filename = Path.GetFullPath(filename);
try
{
if (CanCreateSparse(filename) == false)
return;
uint bytesReturned = 0;
const uint access = (uint) 0x40000000; // GenericWrite
const int sharing = 0; // none
const uint attributes = (uint) 0x00000080; // Normal
const uint creation = (uint) 1; // Only create if new
using (var handle = CreateFileW(filename, access, sharing, IntPtr.Zero, creation, attributes, IntPtr.Zero))
{
// If we couldn't create the file, bail out
if (handle.IsInvalid)
return;
// If we can't set the sparse bit, bail out
if (!DeviceIoControl(handle, FSCTL_SET_SPARSE, IntPtr.Zero, 0, IntPtr.Zero, 0, ref bytesReturned, IntPtr.Zero))
return;
// Tell the filesystem to mark bytes 0 -> length as sparse zeros
var data = new FILE_ZERO_DATA_INFORMATION(0, length);
var structSize = (uint) Marshal.SizeOf(data);
var ptr = Marshal.AllocHGlobal((int) structSize);
try
{
Marshal.StructureToPtr(data, ptr, false);
DeviceIoControl(handle, FSCTL_SET_ZERO_DATA, ptr,
structSize, IntPtr.Zero, 0, ref bytesReturned, IntPtr.Zero);
}
finally
{
Marshal.FreeHGlobal(ptr);
}
}
}
catch (DllNotFoundException)
{
SupportsSparse = false;
}
catch (EntryPointNotFoundException)
{
SupportsSparse = false;
}
catch
{
// Ignore for now. Maybe if i keep hitting this i should abort future attemts
}
}