第11.16章: Wine 文件 API
概述
Wine(“Wine Is Not an Emulator”)让 Windows 二进制程序能在 Linux、FreeBSD 等 POSIX 系统上运行。Wine 通过把 Win32 与 NT API 翻译成宿主系统调用来实现它们 — 而那些宿主系统调用最终使用的就是 POSIX 文件描述符。
当 fast_io 作为 Wine 自身的一部分构建时(或者用于在 Wine 下运行、需要直接与宿主打交道的代码时),它通过下面这些类型暴露这一层:
-
::fast_io::wine_file— 对 Wine 宿主文件描述符的 RAII 拥有式包装。 -
::fast_io::wine_io_observer— 对已有 Wine 宿主文件描述符的非拥有视图。
注意:上游 fast_io 中的 Wine 层尚未完成。本节描述的是它按计划落地时的设计。不过这些概念与你在 POSIX、Win32、NT 上已经见过的 RAII / observer 模式完全一致。
模式是一样的
fast_io 中的每一层都遵循同样的形状:
- 一个名为
xxx_file的拥有式 RAII 类型。 - 一个名为
xxx_io_observer的非拥有观察者类型。 - 对
print、println与scan的完整支持。 - 能够包裹来自外部代码的原始句柄。
wine_file 也不例外。概念上它长这样:
#include <fast_io.h>
#include <fast_io_device.h>
int main()
{
using namespace ::fast_io::iomnp;
// Opens a file through the Wine host layer.
::fast_io::wine_file wf(u8"hello_wine.txt", ::fast_io::open_mode::out);
print(wf, "Hello from wine_file!\n");
::std::size_t const n{42zu};
println(wf, "The answer is: ", n);
}
包裹 Wine 宿主文件描述符
当 Wine 翻译一次 Windows CreateFileW 调用时,它最终会产生一个宿主 POSIX 文件描述符。你可以把这个描述符包进 wine_io_observer,从而通过 fast_io 继续使用它:
#include <fast_io.h>
#include <fast_io_device.h>
void write_via_wine(int host_fd)
{
using namespace ::fast_io::iomnp;
// Non-owning view over Wine's host fd.
::fast_io::wine_io_observer observer{
static_cast<::fast_io::wine_io_observer::native_handle_type>(host_fd)};
println(observer, u8"Written through a wine_io_observer\n");
}
为什么需要这一层?
Wine 是一套复杂的基础设施。位于 Wine 内部的代码(例如 Wine 自己的 ntdll.dll 或 kernel32.dll 实现)需要:
-
从客户代码那里接收一个 Windows
HANDLE。 -
通过 Wine 的内部表把它翻译成宿主
int fd。 -
在那个
fd上执行宿主 I/O,同时仍能把错误以 NTSTATUS 码的形式呈现给客户。
wine_file 让 Wine 开发者获得与其他层一样的 RAII / observer 使用体验,而不必在每个调用点手写资源管理。
与其他层的关系
在运行 Wine 的 POSIX 宿主上,完整的分层是这样的:
-
客户的 Windows 二进制程序调用
WriteFile,这在 Wine 内部解析为ntdll!NtWriteFile。 -
Wine 的
ntdll把它翻译成对宿主 fd 的一次 POSIXwrite(2)调用 — 而wine_file包裹的正是这个 fd。
因此从客户的角度,I/O 走的是 NT 层;从宿主的角度,走的是 POSIX。wine_file 就住在两者之间的接缝上。
小结
-
::fast_io::wine_file是 Wine 宿主文件描述符的 RAII 包装。 -
::fast_io::wine_io_observer是非拥有视图。 -
Wine 层仍在开发中,但它的设计与
posix_file、win32_file、nt_file完全同构。 - 它位于 Windows 客户与 Wine 所运行的 POSIX 宿主之间的边界上。