using System.Runtime.InteropServices; using Microsoft.Win32.SafeHandles; namespace XFESystem.Kernel; /// /// NativeAOT PAL scatter/gather I/O implemented through Cosmos's existing /// plugged positional single-buffer I/O. It preserves short-read semantics. /// public static unsafe class VectorFileIo { [StructLayout(LayoutKind.Sequential)] public struct IoVector { public byte* Base; public nuint Count; } [UnmanagedCallersOnly(EntryPoint = "SystemNative_PReadV")] public static long Read(nint descriptor, IoVector* vectors, int count, long offset) => Transfer(descriptor, vectors, count, offset, false); [UnmanagedCallersOnly(EntryPoint = "SystemNative_PWriteV")] public static long Write(nint descriptor, IoVector* vectors, int count, long offset) => Transfer(descriptor, vectors, count, offset, true); public static long Transfer(nint descriptor, IoVector* vectors, int count, long offset, bool write) { if (count < 0 || count > 1024 || offset < 0 || count > 0 && vectors == null) return Fail(0x1001C); // .NET PAL EINVAL if (count == 0) return 0; long total = 0; try { using var handle = new SafeFileHandle(descriptor, ownsHandle: false); for (var index = 0; index < count; index++) { var vector = vectors[index]; if (vector.Count > int.MaxValue || vector.Count != 0 && vector.Base == null) return total == 0 ? Fail(0x1001C) : total; var length = (int)vector.Count; if (length == 0) continue; if (offset > long.MaxValue - total || offset + total > long.MaxValue - length) return total == 0 ? Fail(0x10040) : total; // PAL EOVERFLOW if (write) { RandomAccess.Write(handle, new ReadOnlySpan(vector.Base, length), offset + total); total += length; } else { int read = RandomAccess.Read(handle, new Span(vector.Base, length), offset + total); total += read; if (read < length) break; } } return total; } catch (Exception error) when (error is IOException or ArgumentException or UnauthorizedAccessException or ObjectDisposedException or NotSupportedException) { int code = error is UnauthorizedAccessException ? 0x10002 : error is ObjectDisposedException ? 0x10008 : error is NotSupportedException ? 0x1003D : error is ArgumentException ? 0x1001C : 0x1001D; return total == 0 ? Fail(code) : total; } } private static long Fail(int error) { Marshal.SetLastPInvokeError(error); return -1; } }