refactor(a2a-client): no runtime-internal native calls for attachments

This commit is contained in:
EugeneTes
2026-10-08 14:09:18 +00:00
parent 0d2583ab01
commit ab714a24ce
2 changed files with 2 additions and 40 deletions

View File

@@ -285,7 +285,7 @@ internal sealed class A2ATool(A2AClientSettings settings, string target, A2AWatc
}
/// <summary>
/// Reads the attachments: regular workspace files (symlinks resolved and confined), together at most
/// Reads the attachments: workspace files (symlinks resolved and confined), together at most
/// <see cref="A2AClientSettings.MaxFileBytes"/>, each read through one opened stream so a file growing meanwhile is
/// still capped.
/// </summary>
@@ -297,7 +297,7 @@ internal sealed class A2ATool(A2AClientSettings settings, string target, A2AWatc
{
var full = ConfinedPath(workspace, path);
if (Directory.Exists(full) || !File.Exists(full)) throw new ArgumentException($"{path} does not exist or is not a file.");
if (!IsRegularFile(full)) throw new ArgumentException($"{path} is not a regular file.");
// Special files (FIFOs, devices) aren't detected: a FIFO would block here until the run is aborted.
byte[] bytes;
await using (var stream = new FileStream(full, new FileStreamOptions
{ Mode = FileMode.Open, Access = FileAccess.Read, Share = FileShare.Read, Options = FileOptions.Asynchronous }))
@@ -321,29 +321,6 @@ internal sealed class A2ATool(A2AClientSettings settings, string target, A2AWatc
return parts;
}
/// <summary>
/// False for FIFOs, sockets and devices, which could block or never end. Unix: the runtime's own stat (the managed
/// API reports every non-directory as a file); elsewhere every existing file counts as regular.
/// </summary>
private static bool IsRegularFile(string path)
{
if (OperatingSystem.IsWindows()) return true;
try
{
var status = new byte[512]; // FileStatus is ~120 bytes; Mode is the second int32
if (SystemNativeStat(path, status) != 0) return false;
const int typeMask = 0xF000, regular = 0x8000;
return (BitConverter.ToInt32(status, 4) & typeMask) == regular;
}
catch (Exception ex) when (ex is DllNotFoundException or EntryPointNotFoundException)
{
return true;
}
}
[System.Runtime.InteropServices.DllImport("libSystem.Native", EntryPoint = "SystemNative_Stat")]
private static extern int SystemNativeStat([System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPUTF8Str)] string path, byte[] status);
/// <summary>The real path of a workspace file: inside the workspace lexically and after every symlink is resolved.</summary>
internal static string ConfinedPath(string workspace, string path)
{