using System; using System.IO; using System.Runtime.InteropServices; namespace SvdCli.Storage { internal static class NativeIoSupport { public static bool SetSparse(this FileStream fileStream) { if (fileStream == null) throw new ArgumentNullException(nameof(fileStream)); if (fileStream.SafeFileHandle == null) throw new ArgumentException($"{nameof(fileStream.SafeFileHandle)} is null", nameof(fileStream)); FILE_SET_SPARSE_BUFFER sparse; sparse.SetSparse = true; uint bytesTransferred; return DeviceIoControl(fileStream.SafeFileHandle.DangerousGetHandle(), 0x900c4/*FSCTL_SET_SPARSE*/, ref sparse, (uint)Marshal.SizeOf(sparse), IntPtr.Zero, 0, out bytesTransferred, IntPtr.Zero); } public static bool Trim(this FileStream fileStream, long offset, long length) { if (fileStream == null) throw new ArgumentNullException(nameof(fileStream)); if (fileStream.SafeFileHandle == null) throw new ArgumentException($"{nameof(fileStream.SafeFileHandle)} is null", nameof(fileStream)); FILE_ZERO_DATA_INFORMATION zero; uint bytesTransferred; zero.FileOffset = offset; zero.BeyondFinalZero = offset + length; return DeviceIoControl(fileStream.SafeFileHandle.DangerousGetHandle(), 0x980c8 /* FSCTL_SET_ZERO_DATA */, ref zero, (uint)Marshal.SizeOf(zero), IntPtr.Zero, 0, out bytesTransferred, IntPtr.Zero); } /* interop */ [StructLayout(LayoutKind.Sequential)] private struct FILE_SET_SPARSE_BUFFER { public bool SetSparse; } [StructLayout(LayoutKind.Sequential)] private struct FILE_ZERO_DATA_INFORMATION { public long FileOffset; public long BeyondFinalZero; } [DllImport("kernel32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.U1)] private static extern bool DeviceIoControl( IntPtr hDevice, uint dwIoControlCode, ref FILE_SET_SPARSE_BUFFER lpInBuffer, uint nInBufferSize, IntPtr lpOutBuffer, uint nOutBufferSize, out uint lpBytesReturned, IntPtr overlapped); [DllImport("kernel32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.U1)] private static extern bool DeviceIoControl( IntPtr hDevice, uint dwIoControlCode, ref FILE_ZERO_DATA_INFORMATION lpInBuffer, uint nInBufferSize, IntPtr lpOutBuffer, uint nOutBufferSize, out uint lpBytesReturned, IntPtr overlapped); } }