XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFESystem

【Rust】XFE系统,基于Rust和汇编

公开
关注 0 Fork 0 Star 0
UTF-8
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;

namespace XFESystem.Kernel;

/// <summary>
/// NativeAOT PAL scatter/gather I/O implemented through Cosmos's existing
/// plugged positional single-buffer I/O. It preserves short-read semantics.
/// </summary>
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<byte>(vector.Base, length), offset + total);
                    total += length;
                }
                else
                {
                    int read = RandomAccess.Read(handle, new Span<byte>(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;
    }
}