MacOS Ventura下.NET 6调用FileStream.SetLength访问Samba共享异常
是否为.NET 6的Bug?
这个问题大概率不是.NET 6本身的Bug,更可能是MacOS Ventura升级到SMB 3.1.1后,.NET FileStream的底层系统调用与新SMB协议的兼容性问题。毕竟仅Ventura系统出现异常,旧系统(BigSur,SMB 3.02)正常,且已排除服务器权限问题,说明问题出在客户端SMB协议与.NET底层实现的适配层面。
问题原因分析
Ventura的SMB 3.1.1在远程文件的长度修改操作上,底层逻辑和旧版本存在差异。.NET 6的FileStream.SetLength调用的是MacOS原生的文件系统API(如ftruncate),而新SMB协议对这类远程文件的扩展操作有更严格的校验或不同的处理流程,导致系统返回输入输出错误(HResult:5对应系统层面的EIO错误)。
解决思路
临时规避:用写入空字节替代SetLength扩展文件
直接跳过SetLength的扩展调用,通过写入空字节的方式让系统自动扩展文件长度,这是最直接的临时解决方案。示例代码:using System.IO; namespace Test { public class Program { static void Main(string[] args) { var filePath = "/Volumes/common/_jq-share/files/test/Database-journal.db"; var stream = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite, 4096); stream.SetLength(stream.Length); // 缩短或保持长度仍可正常使用 // 替换原SetLength扩展逻辑 ExtendFileStream(stream, stream.Length + 1); } static void ExtendFileStream(FileStream stream, long targetLength) { if (targetLength <= stream.Length) { stream.SetLength(targetLength); return; } stream.Position = targetLength - 1; stream.WriteByte(0); stream.Flush(); } } }强制使用旧版SMB协议挂载共享
尝试让Mac用旧版SMB 3.02协议挂载共享,绕开新协议的兼容性问题:- 终端手动挂载:
mount_smbfs //你的用户名@服务器地址/共享名 /Volumes/common/_jq-share -o vers=3.02 - 自动挂载配置:编辑
/etc/nsmb.conf文件(不存在则新建),添加以下内容:
保存后重启Mac或重新挂载共享即可生效。[default] protocol_vers_map=3.02
- 终端手动挂载:
升级.NET版本到更高版本
尝试升级到.NET 7或.NET 8,后续版本可能针对MacOS Ventura的SMB兼容性做了适配修复。虽然.NET 6是LTS版本,但新版本的系统适配更完善,大概率能解决这类协议兼容问题。提交反馈给.NET官方
如果以上方案都无效,可在.NET官方GitHub仓库提交Issue,附上复现代码、系统版本、SMB协议版本等信息,帮助官方定位并修复这个兼容性问题。
内容的提问来源于stack exchange,提问作者Jonny Quarta

