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

XFESystem

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

公开
关注 0 Fork 0 Star 0
UTF-8
namespace XFESystem.Storage;

// Every seek and unaligned metadata write remains inside one validated
// partition. A filesystem never receives a whole-device stream.
public sealed class PartitionStream : Stream
{
    readonly IPhysicalDisk disk;
    readonly DiskPartition partition;
    readonly bool writable;
    long position;
    public PartitionStream(IPhysicalDisk disk,DiskPartition partition,bool writable)
    {
        this.disk=disk;this.partition=partition;this.writable=writable&&disk.CanWrite&&partition.DataPartition;
        if(partition.Start>=disk.SectorCount||partition.Count==0||partition.Count>disk.SectorCount-partition.Start||partition.Count>(ulong)long.MaxValue/512)throw new IOException("Invalid partition stream extent.");
    }
    public override bool CanRead=>true;
    public override bool CanSeek=>true;
    public override bool CanWrite=>writable;
    public override long Length=>checked((long)partition.Count*512);
    public override long Position {get=>position;set{if(value<0||value>Length)throw new IOException("Seek leaves partition.");position=value;}}
    public override long Seek(long offset,SeekOrigin origin)
    {Position=checked((origin switch {SeekOrigin.Begin=>0L,SeekOrigin.Current=>position,SeekOrigin.End=>Length,_=>throw new ArgumentException("Invalid seek origin.")})+offset);return position;}
    public override void Flush()=>disk.Flush();
    public override void SetLength(long value)=>throw new NotSupportedException("Partition resizing is not supported.");
    public override int Read(byte[] buffer,int offset,int count)=>Read(buffer.AsSpan(offset,count));
    public override int Read(Span<byte> buffer)
    {
        int total=(int)Math.Min(buffer.Length,Length-position),done=0;
        while(done<total)
        {
            int skip=(int)(position&511),copy=Math.Min(total-done,32768-skip),bytes=(skip+copy+511)&~511;
            byte[] sectors=new byte[bytes];disk.Read(partition.Start+(ulong)position/512,sectors);
            sectors.AsSpan(skip,copy).CopyTo(buffer[done..]);position+=copy;done+=copy;
        }
        return done;
    }
    public override void Write(byte[] buffer,int offset,int count)=>Write(buffer.AsSpan(offset,count));
    public override void Write(ReadOnlySpan<byte> buffer)
    {
        if(!writable)throw new UnauthorizedAccessException("This volume is read-only.");
        if(buffer.Length>Length-position)throw new IOException("Write leaves partition.");
        while(!buffer.IsEmpty)
        {
            int skip=(int)(position&511),copy=Math.Min(buffer.Length,32768-skip),bytes=(skip+copy+511)&~511;
            byte[] sectors=new byte[bytes];ulong lba=partition.Start+(ulong)position/512;
            if(skip!=0||copy!=bytes)disk.Read(lba,sectors);
            buffer[..copy].CopyTo(sectors.AsSpan(skip));disk.AuthorizePartition(partition.Start,partition.Count);disk.Write(lba,sectors);
            position+=copy;buffer=buffer[copy..];
        }
    }
}