| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155 |
- using System;
- using System.IO;
- using System.Runtime.InteropServices;
- using System.Runtime.Versioning;
- namespace Ryujinx.Common.SystemInterop
- {
- [SupportedOSPlatform("linux")]
- [SupportedOSPlatform("macos")]
- public partial class UnixStream : Stream, IDisposable
- {
- private const int InvalidFd = -1;
- private int _fd;
- [LibraryImport("libc", SetLastError = true)]
- private static partial long read(int fd, IntPtr buf, ulong count);
- [LibraryImport("libc", SetLastError = true)]
- private static partial long write(int fd, IntPtr buf, ulong count);
- [LibraryImport("libc", SetLastError = true)]
- private static partial int close(int fd);
- public UnixStream(int fd)
- {
- if (InvalidFd == fd)
- {
- throw new ArgumentException("Invalid file descriptor");
- }
- _fd = fd;
-
- CanRead = read(fd, IntPtr.Zero, 0) != -1;
- CanWrite = write(fd, IntPtr.Zero, 0) != -1;
- }
- ~UnixStream()
- {
- Close();
- }
- public override bool CanRead { get; }
- public override bool CanWrite { get; }
- public override bool CanSeek => false;
- public override long Length => throw new NotSupportedException();
- public override long Position
- {
- get => throw new NotSupportedException();
- set => throw new NotSupportedException();
- }
- public override void Flush()
- {
- }
- public override unsafe int Read([In, Out] byte[] buffer, int offset, int count)
- {
- if (offset < 0 || offset > (buffer.Length - count) || count < 0)
- {
- throw new ArgumentOutOfRangeException();
- }
- if (buffer.Length == 0)
- {
- return 0;
- }
- long r = 0;
- fixed (byte* buf = &buffer[offset])
- {
- do
- {
- r = read(_fd, (IntPtr)buf, (ulong)count);
- } while (ShouldRetry(r));
- }
- return (int)r;
- }
-
- public override unsafe void Write(byte[] buffer, int offset, int count)
- {
- if (offset < 0 || offset > (buffer.Length - count) || count < 0)
- {
- throw new ArgumentOutOfRangeException();
- }
- if (buffer.Length == 0)
- {
- return;
- }
- fixed (byte* buf = &buffer[offset])
- {
- long r = 0;
- do {
- r = write(_fd, (IntPtr)buf, (ulong)count);
- } while (ShouldRetry(r));
- }
- }
- public override long Seek(long offset, SeekOrigin origin)
- {
- throw new NotSupportedException();
- }
- public override void SetLength(long value)
- {
- throw new NotSupportedException();
- }
- public override void Close()
- {
- if (_fd == InvalidFd)
- {
- return;
- }
- Flush();
- int r;
- do {
- r = close(_fd);
- } while (ShouldRetry(r));
- _fd = InvalidFd;
- }
- void IDisposable.Dispose()
- {
- Close();
- }
- private bool ShouldRetry(long r)
- {
- if (r == -1)
- {
- const int eintr = 4;
- int errno = Marshal.GetLastPInvokeError();
- if (errno == eintr)
- {
- return true;
- }
- throw new SystemException($"Operation failed with error 0x{errno:X}");
- }
- return false;
- }
- }
- }
|