使用 std::fs::copy 将文件复制到网络共享 (SMB) 时过时的文件句柄

Stale file handles when copying files to network share (SMB) with std::fs::copy

提问人:Aleksandar Dimitrov 提问时间:10/5/2023 更新时间:10/5/2023 访问量:93

问:

我编写了一个小程序,用于在 Rust 中以系统的方式将文件复制到网络共享,用于完成繁重的工作。网络共享是通过 Samba 在 Linux 上挂载的 CIFS 。它曾经使用协议的第一个版本(很久以前已被弃用)。坐骑看起来像这样:std::fs::copy

sudo mount -t cifs -o vers=1.0 //remote /mountpoint

复制文件的 Rust 代码如下所示

std::fs::copy(source_file.path(), target_directory.join(source_file.file_name()))?;

这很顺利。

遥控器的服务器软件已更新,我可以删除挂载的参数。据推测,它现在使用一些更新的版本。vers=1.0

但是,现在同一个程序失败并出现错误:

Stale file handle (os error 116)

strace报告打开远程文件进行写入产生了错误:

openat(AT_FDCWD, "/origin/file", O_RDONLY|O_CLOEXEC) = 4
statx(4, "", AT_STATX_SYNC_AS_STAT|AT_EMPTY_PATH, STATX_ALL, {stx_mask=STATX_ALL|STATX_MNT_ID, stx_attributes=0, stx_mode=S_IFREG|0755, stx_size=30566455, ...}) = 0
openat(AT_FDCWD, "/remote_mountpoint/file", O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, 0100755) = 5
statx(5, "", AT_STATX_SYNC_AS_STAT|AT_EMPTY_PATH, STATX_ALL, 0x7fffe81df6c0) = -1 ESTALE (Stale file handle)

因此,调用在上一个调用中刚刚打开的文件句柄突然“过时”。statx

你知道为什么,我该如何补救吗?是错误吗?std::fs::copy

我在这里有点不够深入,但这可能是因为尝试复制元数据并且使用不知何故不受支持的新 CIFS 版本?std::fs::copy

请注意,复制 using 和 有效。std::fs::Filestd::io::copy

let mut source = fs::File::open(&source_file.path())?;
let mut target = fs::File::create(import_directory.join(source_file.file_name()))?;
std::io::copy(&mut source, &mut target)?;

这是我完全不明白的一点这也会导致文件句柄过时但它有效。 显示:strace

openat(AT_FDCWD, "/origin/file", O_RDONLY|O_CLOEXEC) = 4
openat(AT_FDCWD, "/remote_mountpoint/file", O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, 0666) = 5
statx(4, "", AT_STATX_SYNC_AS_STAT|AT_EMPTY_PATH, STATX_ALL, {stx_mask=STATX_ALL|STATX_MNT_ID, stx_attributes=0, stx_mode=S_IFREG|0755, stx_size=4590679, ...}) = 0
statx(5, "", AT_STATX_SYNC_AS_STAT|AT_EMPTY_PATH, STATX_ALL, 0x7fffc29e56e0) = -1 ESTALE (Stale file handle)

因此,系统调用不是以相同的顺序进行的(将其调用放在第二次调用之前),但最终结果是相同的:在远程文件句柄上返回。但是中止,并继续将其错误输出写入屏幕,然后愉快地继续调用和系统调用,最终复制文件就好了。std::fs::copystatxopenatstatx-1 ESTALEstd::fs::copystd::io::copyreadwrite

我对这个解决方案很满意,没有理由更喜欢,但我想知道前者失败的原因,以及后者是否是我唯一的选择。std::fs::copystd::io::copy

Linux Rust 桑巴

评论

0赞 Aleksandar Dimitrov 10/5/2023
我的猜测是,这实际上需要结果,而不是,因此很乐意继续。不过,我仍然不知道为什么首先会发生过时的文件句柄错误。fs::copystatxio::copy
0赞 Barmar 10/5/2023
我怀疑它用于避免一些可能导致安全漏洞的竞争条件,但 CIFS 没有正确实现它。Unix 文件描述符概念并不总是直接映射到某些文件共享协议。openat()
0赞 Barmar 10/5/2023
我的猜测是它在创建新文件时无法正常工作,只有在打开现有文件时才能正常工作。
0赞 Barmar 10/5/2023
至于为什么第二个测试有效,我怀疑 Rust 函数忽略了statx()
0赞 Aleksandar Dimitrov 10/5/2023
@Barmar感谢您的输入。在所有情况下,文件都是创建的,以前不存在。我同意,第二种方式可能只是对 的错误条件不感兴趣。我想知道为什么它需要执行它。statx

答: 暂无答案