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)) return; // Create a file with the sparse flag enabled uint bytesReturned = 0; uint access = 0x40000000; // GenericWrite uint sharing = 0; // none uint attributes = 0x00000080; // Normal uint creation = 1; // Only create if new using (SafeFileHandle 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 FILE_ZERO_DATA_INFORMATION data = new FILE_ZERO_DATA_INFORMATION(0, length); uint structSize = (uint)Marshal.SizeOf(data); IntPtr 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 } }
private static extern Boolean DeviceIoControl( IntPtr hDevice, UInt32 dwIoControlCode, ref FILE_ZERO_DATA_INFORMATION lpInBuffer, UInt32 nInBufferSize, IntPtr lpOutBuffer, UInt32 nOutBufferSize, out UInt32 lpBytesReturned, IntPtr Overlapped);
/// <summary><see cref="http://msdn.microsoft.com/en-us/library/windows/desktop/aa364597(v=vs.85).aspx"/></summary> public void FileSystemSetZeroData(long fileOffset, long length) { FILE_ZERO_DATA_INFORMATION input = new FILE_ZERO_DATA_INFORMATION(); input.FileOffset = fileOffset; input.BeyondFinalZero = fileOffset + length; DeviceIoControlHelper.InvokeIoControl(Handle, IOControlCode.FsctlSetZeroData, input); }
private static extern bool ZeroFileDeviceIoControl( SafeFileHandle handle, uint ioControlCode, [In] ref FILE_ZERO_DATA_INFORMATION fzdi, uint inBufferSize, IntPtr pv1, uint outBufferSize, out uint bytesReturned, IntPtr pv2);
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)) { return; } // Create a file with the sparse flag enabled uint bytesReturned = 0; uint access = 0x40000000; // GenericWrite uint sharing = 0; // none uint attributes = 0x00000080; // Normal uint creation = 1; // Only create if new using SafeFileHandle 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); uint structSize = (uint)Marshal.SizeOf(data); IntPtr 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 } }
internal static unsafe void ZeroFile(SafeFileHandle handle, ulong uptoOffset) { uint temp; FILE_ZERO_DATA_INFORMATION fzdi = new FILE_ZERO_DATA_INFORMATION(0, (long)uptoOffset); bool success = ZeroFileDeviceIoControl(handle, FSCTL_SET_ZERO_DATA, ref fzdi, (uint)sizeof(FILE_ZERO_DATA_INFORMATION), IntPtr.Zero, 0, out temp, IntPtr.Zero); if (success == false) { throw new Win32Exception(Marshal.GetLastWin32Error()); } return; }
public async Task DeviceIOControlAsync_Overlapped_Works() { const uint FSCTL_SET_ZERO_DATA = 0x000980c8; string fileName = Path.GetTempFileName(); try { using (var file = CreateFile( filename: fileName, access: Kernel32.ACCESS_MASK.GenericRight.GENERIC_READ | ACCESS_MASK.GenericRight.GENERIC_WRITE, share: Kernel32.FileShare.FILE_SHARE_READ | Kernel32.FileShare.FILE_SHARE_WRITE, securityAttributes: IntPtr.Zero, creationDisposition: CreationDisposition.CREATE_ALWAYS, flagsAndAttributes: CreateFileFlags.FILE_FLAG_OVERLAPPED, SafeObjectHandle.Null)) { Assert.False(file.IsInvalid); Assert.True(ThreadPool.BindHandle(file)); var data = new FILE_ZERO_DATA_INFORMATION[] { new FILE_ZERO_DATA_INFORMATION { BeyondFinalZero = int.MaxValue }, }; uint ret = await Kernel32.DeviceIoControlAsync <FILE_ZERO_DATA_INFORMATION, byte>( file, (int)FSCTL_SET_ZERO_DATA, data, null, CancellationToken.None); Assert.Equal(0u, ret); } } finally { File.Delete(fileName); } }