Compare commits

..

4 Commits

Author SHA1 Message Date
gdkchan
44862dce3e Stub unsupported BSD socket options (#5670)
* Stub unsupported BSD socket options

* Span.Clear
2023-09-19 19:35:56 +02:00
Emmanuel Hansen
e601419bd4 make cheat list binding public (#5697) 2023-09-19 16:51:56 +00:00
Emmanuel Hansen
d6bc0de785 use compiled bidning for localizations (#5684) 2023-09-18 22:20:59 +02:00
Emmanuel Hansen
9f26fd3600 remove some usages of reflection binding (#5686) 2023-09-18 22:09:22 +02:00
10 changed files with 195 additions and 39 deletions

View File

@@ -1,6 +1,7 @@
using Avalonia.Data; using Avalonia.Data.Core;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using Avalonia.Markup.Xaml.MarkupExtensions; using Avalonia.Markup.Xaml.MarkupExtensions;
using Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings;
using System; using System;
namespace Ryujinx.Ava.Common.Locale namespace Ryujinx.Ava.Common.Locale
@@ -18,11 +19,20 @@ namespace Ryujinx.Ava.Common.Locale
{ {
LocaleKeys keyToUse = Key; LocaleKeys keyToUse = Key;
ReflectionBindingExtension binding = new($"[{keyToUse}]") var builder = new CompiledBindingPathBuilder();
builder.SetRawSource(LocaleManager.Instance)
.Property(new ClrPropertyInfo("Item",
obj => (LocaleManager.Instance[keyToUse]),
null,
typeof(string)), (weakRef, iPropInfo) =>
{ {
Mode = BindingMode.OneWay, return PropertyInfoAccessorFactory.CreateInpcPropertyAccessor(weakRef, iPropInfo);
Source = LocaleManager.Instance, });
};
var path = builder.Build();
var binding = new CompiledBindingExtension(path);
return binding.ProvideValue(serviceProvider); return binding.ProvideValue(serviceProvider);
} }

View File

@@ -6,9 +6,11 @@
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale" xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="{locale:Locale ErrorWindowTitle}" Title="{locale:Locale ErrorWindowTitle}"
xmlns:views="using:Ryujinx.Ava.UI.Applet"
Width="450" Width="450"
Height="340" Height="340"
CanResize="False" CanResize="False"
x:DataType="views:ErrorAppletWindow"
SizeToContent="Height" SizeToContent="Height"
mc:Ignorable="d" mc:Ignorable="d"
Focusable="True"> Focusable="True">
@@ -38,7 +40,7 @@
Grid.Column="1" Grid.Column="1"
Margin="10" Margin="10"
VerticalAlignment="Stretch" VerticalAlignment="Stretch"
Text="{ReflectionBinding Message}" Text="{Binding Message}"
TextWrapping="Wrap" /> TextWrapping="Wrap" />
<StackPanel <StackPanel
Name="ButtonStack" Name="ButtonStack"

View File

@@ -4,7 +4,9 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:views="using:Ryujinx.Ava.UI.Controls"
Width="400" Width="400"
x:DataType="views:SwkbdAppletDialog"
mc:Ignorable="d" mc:Ignorable="d"
Focusable="True"> Focusable="True">
<Grid <Grid
@@ -34,13 +36,13 @@
Grid.Row="1" Grid.Row="1"
Grid.Column="1" Grid.Column="1"
Margin="5" Margin="5"
Text="{ReflectionBinding MainText}" Text="{Binding MainText}"
TextWrapping="Wrap" /> TextWrapping="Wrap" />
<TextBlock <TextBlock
Grid.Row="2" Grid.Row="2"
Grid.Column="1" Grid.Column="1"
Margin="5" Margin="5"
Text="{ReflectionBinding SecondaryText}" Text="{Binding SecondaryText}"
TextWrapping="Wrap" /> TextWrapping="Wrap" />
<TextBox <TextBox
Name="Input" Name="Input"
@@ -50,7 +52,7 @@
VerticalAlignment="Center" VerticalAlignment="Center"
Focusable="True" Focusable="True"
KeyUp="Message_KeyUp" KeyUp="Message_KeyUp"
Text="{ReflectionBinding Message}" Text="{Binding Message}"
TextInput="Message_TextInput" TextInput="Message_TextInput"
TextWrapping="Wrap" TextWrapping="Wrap"
UseFloatingWatermark="True" /> UseFloatingWatermark="True" />

View File

@@ -46,7 +46,7 @@
<Setter Property="CornerRadius" Value="4" /> <Setter Property="CornerRadius" Value="4" />
</Style> </Style>
<Style Selector="ListBoxItem:selected /template/ Rectangle#SelectionIndicator"> <Style Selector="ListBoxItem:selected /template/ Rectangle#SelectionIndicator">
<Setter Property="MinHeight" Value="{ReflectionBinding $parent[UserControl].DataContext.GridItemSelectorSize}" /> <Setter Property="MinHeight" Value="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).GridItemSelectorSize}" />
</Style> </Style>
</ListBox.Styles> </ListBox.Styles>
<ListBox.ItemTemplate> <ListBox.ItemTemplate>
@@ -56,10 +56,10 @@
Margin="10" Margin="10"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" VerticalAlignment="Stretch"
Classes.huge="{ReflectionBinding $parent[UserControl].DataContext.IsGridHuge}" Classes.huge="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).IsGridHuge}"
Classes.large="{ReflectionBinding $parent[UserControl].DataContext.IsGridLarge}" Classes.large="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).IsGridLarge}"
Classes.normal="{ReflectionBinding $parent[UserControl].DataContext.IsGridMedium}" Classes.normal="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).IsGridMedium}"
Classes.small="{ReflectionBinding $parent[UserControl].DataContext.IsGridSmall}" Classes.small="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).IsGridSmall}"
ClipToBounds="True" ClipToBounds="True"
CornerRadius="4"> CornerRadius="4">
<Grid> <Grid>
@@ -78,7 +78,7 @@
Margin="0,10,0,0" Margin="0,10,0,0"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" VerticalAlignment="Stretch"
IsVisible="{ReflectionBinding $parent[UserControl].DataContext.ShowNames}"> IsVisible="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).ShowNames}">
<TextBlock <TextBlock
HorizontalAlignment="Center" HorizontalAlignment="Center"
VerticalAlignment="Center" VerticalAlignment="Center"

View File

@@ -42,7 +42,7 @@
</ListBox.ItemsPanel> </ListBox.ItemsPanel>
<ListBox.Styles> <ListBox.Styles>
<Style Selector="ListBoxItem:selected /template/ Rectangle#SelectionIndicator"> <Style Selector="ListBoxItem:selected /template/ Rectangle#SelectionIndicator">
<Setter Property="MinHeight" Value="{ReflectionBinding $parent[UserControl].DataContext.ListItemSelectorSize}" /> <Setter Property="MinHeight" Value="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).ListItemSelectorSize}" />
</Style> </Style>
</ListBox.Styles> </ListBox.Styles>
<ListBox.ItemTemplate> <ListBox.ItemTemplate>
@@ -67,10 +67,10 @@
Grid.RowSpan="3" Grid.RowSpan="3"
Grid.Column="0" Grid.Column="0"
Margin="0" Margin="0"
Classes.huge="{ReflectionBinding $parent[UserControl].DataContext.IsGridHuge}" Classes.huge="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).IsGridHuge}"
Classes.large="{ReflectionBinding $parent[UserControl].DataContext.IsGridLarge}" Classes.large="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).IsGridLarge}"
Classes.normal="{ReflectionBinding $parent[UserControl].DataContext.IsGridMedium}" Classes.normal="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).IsGridMedium}"
Classes.small="{ReflectionBinding $parent[UserControl].DataContext.IsGridSmall}" Classes.small="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).IsGridSmall}"
Source="{Binding Icon, Converter={StaticResource ByteImage}}" /> Source="{Binding Icon, Converter={StaticResource ByteImage}}" />
<Border <Border
Grid.Column="2" Grid.Column="2"

View File

@@ -11,6 +11,7 @@
Height="500" Height="500"
MinWidth="500" MinWidth="500"
MinHeight="500" MinHeight="500"
x:DataType="window:CheatWindow"
WindowStartupLocation="CenterOwner" WindowStartupLocation="CenterOwner"
mc:Ignorable="d" mc:Ignorable="d"
Focusable="True"> Focusable="True">
@@ -40,7 +41,7 @@
HorizontalAlignment="Center" HorizontalAlignment="Center"
VerticalAlignment="Center" VerticalAlignment="Center"
LineHeight="18" LineHeight="18"
Text="{ReflectionBinding Heading}" Text="{Binding Heading}"
TextAlignment="Center" TextAlignment="Center"
TextWrapping="Wrap" /> TextWrapping="Wrap" />
<TextBlock <TextBlock
@@ -61,7 +62,7 @@
MinWidth="160" MinWidth="160"
HorizontalAlignment="Center" HorizontalAlignment="Center"
VerticalAlignment="Center" VerticalAlignment="Center"
Text="{ReflectionBinding BuildId}" Text="{Binding BuildId}"
IsReadOnly="True" /> IsReadOnly="True" />
<Border <Border
Grid.Row="3" Grid.Row="3"
@@ -77,7 +78,7 @@
MinHeight="300" MinHeight="300"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" VerticalAlignment="Stretch"
ItemsSource="{ReflectionBinding LoadedCheats}"> ItemsSource="{Binding LoadedCheats}">
<TreeView.Styles> <TreeView.Styles>
<Styles> <Styles>
<Style Selector="TreeViewItem:empty /template/ ItemsPresenter"> <Style Selector="TreeViewItem:empty /template/ ItemsPresenter">
@@ -120,15 +121,15 @@
Name="SaveButton" Name="SaveButton"
MinWidth="90" MinWidth="90"
Margin="5" Margin="5"
Command="{ReflectionBinding Save}" Command="{Binding Save}"
IsVisible="{ReflectionBinding !NoCheatsFound}"> IsVisible="{Binding !NoCheatsFound}">
<TextBlock Text="{locale:Locale SettingsButtonSave}" /> <TextBlock Text="{locale:Locale SettingsButtonSave}" />
</Button> </Button>
<Button <Button
Name="CancelButton" Name="CancelButton"
MinWidth="90" MinWidth="90"
Margin="5" Margin="5"
Command="{ReflectionBinding Close}"> Command="{Binding Close}">
<TextBlock Text="{locale:Locale InputDialogCancel}" /> <TextBlock Text="{locale:Locale InputDialogCancel}" />
</Button> </Button>
</DockPanel> </DockPanel>

View File

@@ -17,7 +17,7 @@ namespace Ryujinx.Ava.UI.Windows
private readonly string _enabledCheatsPath; private readonly string _enabledCheatsPath;
public bool NoCheatsFound { get; } public bool NoCheatsFound { get; }
private AvaloniaList<CheatsList> LoadedCheats { get; } public AvaloniaList<CheatsList> LoadedCheats { get; }
public string Heading { get; } public string Heading { get; }
public string BuildId { get; } public string BuildId { get; }

View File

@@ -39,14 +39,14 @@
Name="EnableAllButton" Name="EnableAllButton"
MinWidth="90" MinWidth="90"
Margin="5" Margin="5"
Command="{ReflectionBinding EnableAll}"> Command="{Binding EnableAll}">
<TextBlock Text="{locale:Locale DlcManagerEnableAllButton}" /> <TextBlock Text="{locale:Locale DlcManagerEnableAllButton}" />
</Button> </Button>
<Button <Button
Name="DisableAllButton" Name="DisableAllButton"
MinWidth="90" MinWidth="90"
Margin="5" Margin="5"
Command="{ReflectionBinding DisableAll}"> Command="{Binding DisableAll}">
<TextBlock Text="{locale:Locale DlcManagerDisableAllButton}" /> <TextBlock Text="{locale:Locale DlcManagerDisableAllButton}" />
</Button> </Button>
</StackPanel> </StackPanel>
@@ -157,14 +157,14 @@
Name="AddButton" Name="AddButton"
MinWidth="90" MinWidth="90"
Margin="5" Margin="5"
Command="{ReflectionBinding Add}"> Command="{Binding Add}">
<TextBlock Text="{locale:Locale SettingsTabGeneralAdd}" /> <TextBlock Text="{locale:Locale SettingsTabGeneralAdd}" />
</Button> </Button>
<Button <Button
Name="RemoveAllButton" Name="RemoveAllButton"
MinWidth="90" MinWidth="90"
Margin="5" Margin="5"
Command="{ReflectionBinding RemoveAll}"> Command="{Binding RemoveAll}">
<TextBlock Text="{locale:Locale DlcManagerRemoveAllButton}" /> <TextBlock Text="{locale:Locale DlcManagerRemoveAllButton}" />
</Button> </Button>
</StackPanel> </StackPanel>

View File

@@ -299,11 +299,21 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
{ {
try try
{ {
LinuxError result = WinSockHelper.ValidateSocketOption(option, level, write: false);
if (result != LinuxError.SUCCESS)
{
Logger.Warning?.Print(LogClass.ServiceBsd, $"Invalid GetSockOpt Option: {option} Level: {level}");
return result;
}
if (!WinSockHelper.TryConvertSocketOption(option, level, out SocketOptionName optionName)) if (!WinSockHelper.TryConvertSocketOption(option, level, out SocketOptionName optionName))
{ {
Logger.Warning?.Print(LogClass.ServiceBsd, $"Unsupported GetSockOpt Option: {option} Level: {level}"); Logger.Warning?.Print(LogClass.ServiceBsd, $"Unsupported GetSockOpt Option: {option} Level: {level}");
optionValue.Clear();
return LinuxError.EOPNOTSUPP; return LinuxError.SUCCESS;
} }
byte[] tempOptionValue = new byte[optionValue.Length]; byte[] tempOptionValue = new byte[optionValue.Length];
@@ -324,11 +334,20 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
{ {
try try
{ {
LinuxError result = WinSockHelper.ValidateSocketOption(option, level, write: true);
if (result != LinuxError.SUCCESS)
{
Logger.Warning?.Print(LogClass.ServiceBsd, $"Invalid SetSockOpt Option: {option} Level: {level}");
return result;
}
if (!WinSockHelper.TryConvertSocketOption(option, level, out SocketOptionName optionName)) if (!WinSockHelper.TryConvertSocketOption(option, level, out SocketOptionName optionName))
{ {
Logger.Warning?.Print(LogClass.ServiceBsd, $"Unsupported SetSockOpt Option: {option} Level: {level}"); Logger.Warning?.Print(LogClass.ServiceBsd, $"Unsupported SetSockOpt Option: {option} Level: {level}");
return LinuxError.EOPNOTSUPP; return LinuxError.SUCCESS;
} }
int value = optionValue.Length >= 4 ? MemoryMarshal.Read<int>(optionValue) : MemoryMarshal.Read<byte>(optionValue); int value = optionValue.Length >= 4 ? MemoryMarshal.Read<int>(optionValue) : MemoryMarshal.Read<byte>(optionValue);

View File

@@ -183,6 +183,104 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
{ BsdSocketOption.TcpKeepCnt, SocketOptionName.TcpKeepAliveRetryCount }, { BsdSocketOption.TcpKeepCnt, SocketOptionName.TcpKeepAliveRetryCount },
}; };
[Flags]
private enum OptionDir
{
Get = 1 << 0,
Set = 1 << 1,
GetSet = Get | Set,
}
private static readonly Dictionary<BsdSocketOption, OptionDir> _validSoSocketOptionMap = new()
{
{ BsdSocketOption.SoDebug, OptionDir.GetSet },
{ BsdSocketOption.SoAcceptConn, OptionDir.Get },
{ BsdSocketOption.SoReuseAddr, OptionDir.GetSet },
{ BsdSocketOption.SoKeepAlive, OptionDir.GetSet },
{ BsdSocketOption.SoDontRoute, OptionDir.GetSet },
{ BsdSocketOption.SoBroadcast, OptionDir.GetSet },
{ BsdSocketOption.SoUseLoopBack, OptionDir.GetSet },
{ BsdSocketOption.SoLinger, OptionDir.GetSet },
{ BsdSocketOption.SoOobInline, OptionDir.GetSet },
{ BsdSocketOption.SoReusePort, OptionDir.GetSet },
{ BsdSocketOption.SoTimestamp, OptionDir.GetSet },
{ BsdSocketOption.SoNoSigpipe, OptionDir.GetSet },
{ BsdSocketOption.SoAcceptFilter, OptionDir.GetSet },
{ BsdSocketOption.SoSndBuf, OptionDir.GetSet },
{ BsdSocketOption.SoRcvBuf, OptionDir.GetSet },
{ BsdSocketOption.SoSndLoWat, OptionDir.GetSet },
{ BsdSocketOption.SoRcvLoWat, OptionDir.GetSet },
{ BsdSocketOption.SoSndTimeo, OptionDir.GetSet },
{ BsdSocketOption.SoRcvTimeo, OptionDir.GetSet },
{ BsdSocketOption.SoError, OptionDir.Get },
{ BsdSocketOption.SoType, OptionDir.Get },
{ BsdSocketOption.SoLabel, OptionDir.Get },
{ BsdSocketOption.SoPeerLabel, OptionDir.Get },
{ BsdSocketOption.SoListenQLimit, OptionDir.Get },
{ BsdSocketOption.SoListenQLen, OptionDir.Get },
{ BsdSocketOption.SoListenIncQLen, OptionDir.Get },
{ BsdSocketOption.SoSetFib, OptionDir.Set },
{ BsdSocketOption.SoUserCookie, OptionDir.Set },
{ BsdSocketOption.SoProtocol, OptionDir.Get },
{ BsdSocketOption.SoBinTime, OptionDir.GetSet },
{ BsdSocketOption.SoNoOffload, OptionDir.Set },
{ BsdSocketOption.SoNoDdp, OptionDir.Set },
{ BsdSocketOption.SoReusePortLb, OptionDir.GetSet },
};
private static readonly Dictionary<BsdSocketOption, OptionDir> _validIpSocketOptionMap = new()
{
{ BsdSocketOption.IpOptions, OptionDir.GetSet },
{ BsdSocketOption.IpHdrIncl, OptionDir.GetSet },
{ BsdSocketOption.IpTos, OptionDir.GetSet },
{ BsdSocketOption.IpTtl, OptionDir.GetSet },
{ BsdSocketOption.IpRecvOpts, OptionDir.GetSet },
{ BsdSocketOption.IpRecvRetOpts, OptionDir.GetSet },
{ BsdSocketOption.IpRecvDstAddr, OptionDir.GetSet },
{ BsdSocketOption.IpRetOpts, OptionDir.GetSet },
{ BsdSocketOption.IpMulticastIf, OptionDir.GetSet },
{ BsdSocketOption.IpMulticastTtl, OptionDir.GetSet },
{ BsdSocketOption.IpMulticastLoop, OptionDir.GetSet },
{ BsdSocketOption.IpAddMembership, OptionDir.GetSet },
{ BsdSocketOption.IpDropMembership, OptionDir.GetSet },
{ BsdSocketOption.IpMulticastVif, OptionDir.GetSet },
{ BsdSocketOption.IpRsvpOn, OptionDir.GetSet },
{ BsdSocketOption.IpRsvpOff, OptionDir.GetSet },
{ BsdSocketOption.IpRsvpVifOn, OptionDir.GetSet },
{ BsdSocketOption.IpRsvpVifOff, OptionDir.GetSet },
{ BsdSocketOption.IpPortRange, OptionDir.GetSet },
{ BsdSocketOption.IpRecvIf, OptionDir.GetSet },
{ BsdSocketOption.IpIpsecPolicy, OptionDir.GetSet },
{ BsdSocketOption.IpOnesBcast, OptionDir.GetSet },
{ BsdSocketOption.IpBindany, OptionDir.GetSet },
{ BsdSocketOption.IpBindMulti, OptionDir.GetSet },
{ BsdSocketOption.IpRssListenBucket, OptionDir.GetSet },
{ BsdSocketOption.IpOrigDstAddr, OptionDir.GetSet },
{ BsdSocketOption.IpRecvTtl, OptionDir.GetSet },
{ BsdSocketOption.IpMinTtl, OptionDir.GetSet },
{ BsdSocketOption.IpDontFrag, OptionDir.GetSet },
{ BsdSocketOption.IpRecvTos, OptionDir.GetSet },
{ BsdSocketOption.IpAddSourceMembership, OptionDir.GetSet },
{ BsdSocketOption.IpDropSourceMembership, OptionDir.GetSet },
{ BsdSocketOption.IpBlockSource, OptionDir.GetSet },
{ BsdSocketOption.IpUnblockSource, OptionDir.GetSet },
};
private static readonly Dictionary<BsdSocketOption, OptionDir> _validTcpSocketOptionMap = new()
{
{ BsdSocketOption.TcpNoDelay, OptionDir.GetSet },
{ BsdSocketOption.TcpMaxSeg, OptionDir.GetSet },
{ BsdSocketOption.TcpNoPush, OptionDir.GetSet },
{ BsdSocketOption.TcpNoOpt, OptionDir.GetSet },
{ BsdSocketOption.TcpMd5Sig, OptionDir.GetSet },
{ BsdSocketOption.TcpInfo, OptionDir.GetSet },
{ BsdSocketOption.TcpCongestion, OptionDir.GetSet },
{ BsdSocketOption.TcpKeepInit, OptionDir.GetSet },
{ BsdSocketOption.TcpKeepIdle, OptionDir.GetSet },
{ BsdSocketOption.TcpKeepIntvl, OptionDir.GetSet },
{ BsdSocketOption.TcpKeepCnt, OptionDir.GetSet },
};
public static LinuxError ConvertError(WsaError errorCode) public static LinuxError ConvertError(WsaError errorCode)
{ {
if (OperatingSystem.IsMacOS()) if (OperatingSystem.IsMacOS())
@@ -221,5 +319,29 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
return table.TryGetValue(option, out name); return table.TryGetValue(option, out name);
} }
public static LinuxError ValidateSocketOption(BsdSocketOption option, SocketOptionLevel level, bool write)
{
var table = level switch
{
SocketOptionLevel.Socket => _validSoSocketOptionMap,
SocketOptionLevel.IP => _validIpSocketOptionMap,
SocketOptionLevel.Tcp => _validTcpSocketOptionMap,
_ => null,
};
OptionDir dir = write ? OptionDir.Set : OptionDir.Get;
if (table == null || !table.TryGetValue(option, out OptionDir validDir))
{
return LinuxError.ENOPROTOOPT;
}
else if ((validDir & dir) != dir)
{
return LinuxError.EOPNOTSUPP;
}
return LinuxError.SUCCESS;
}
} }
} }