mirror of
https://github.com/GreemDev/Ryujinx
synced 2024-11-22 17:56:59 +01:00
9b1cc2cec6
* Logging: Redirect StdErr into logging system * Remove Mono.Unix * Apply suggestions from code review Co-authored-by: riperiperi <rhy3756547@hotmail.com> * Address comments --------- Co-authored-by: Mary <thog@protonmail.com> Co-authored-by: riperiperi <rhy3756547@hotmail.com> Co-authored-by: Mary <mary@mary.zone>
155 lines
3.8 KiB
C#
155 lines
3.8 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|