在 Go 的 Plan 9(plan9)平台实现中,Stat_t 类型并不存在;其功能由 *syscall.Dir 类型替代,该类型用于解析 9P 协议的 stat 消息,并作为 os.FileInfo.Sys() 方法的底层返回值。
在 go 的 plan 9(plan9)平台实现中,`stat_t` 类型并不存在;其功能由 `*syscall.dir` 类型替代,该类型用于解析 9p 协议的 stat 消息,并作为 `os.fileinfo.sys()` 方法的底层返回值。
Go 标准库对不同操作系统的系统调用抽象采取了差异化设计。在 Linux、Darwin 或 Windows 等平台上,os.Stat() 返回的 FileInfo 底层通常封装了类似 syscall.Stat_t 的结构体;但在 Plan 9 中,这一角色由 *syscall.Dir 完全承担。
Plan 9 使用 9P 文件协议,其元数据通过固定格式的二进制 stat 消息传输(长度前缀 + 目录条目结构)。Go 运行时并不预先定义 C 风格的 struct stat,而是通过 syscall.UnmarshalDir 将原始字节流解码为 Go 原生结构:
// 示例:获取并检查 Plan 9 下的 Dir 结构
fi, err := os.Stat("/bin/rc")
if err != nil {
log.Fatal(err)
}
// 获取底层 *syscall.Dir(仅在 GOOS=plan9 下有效)
if dir := fi.Sys(); dir != nil {
if d, ok := dir.(*syscall.Dir); ok {
fmt.Printf("Name: %s, Type: %d, Mode: 0%o, Length: %d\n",
d.Name, d.Type, d.Mode, d.Length)
}
}关键路径如下:
- os.Stat(path) → 调用 dirstat(path)(os/stat_plan9.go)
- dirstat → 调用 syscall.Stat(buf)(syscall/syscall_plan9.go)→ 执行底层 stat(2) 系统调用,写入原始字节到缓冲区
- 缓冲区经 syscall.UnmarshalDir 解析 → 返回 *syscall.Dir 实例
- 最终由 fileInfoFromStat 封装为 os.FileInfo,且 fi.Sys() 直接返回该 *syscall.Dir
⚠️ 注意事项:
- *syscall.Dir 是 Plan 9 特有类型,不可跨平台使用;在非 plan9 构建环境下该类型不可见,fi.Sys() 将返回 nil 或其他平台特定类型。
- syscall.Dir 字段语义直接映射 9P 协议规范(如 Type 表示 QID.type,Dev 表示 QID.dev),而非 POSIX 的 st_mode/st_uid 等字段。
- 若需可移植元数据访问,请始终通过 os.FileInfo 接口方法(如 Name(), Size(), Mode(), ModTime())操作,避免直接依赖 Sys()。
综上,Plan 9 下没有 Stat_t,但有更契合其协议设计的 *syscall.Dir——它是 Go 对 9P stat 消息的原生、安全、零拷贝解码结果,也是深入理解 Plan 9 文件系统交互的关键入口。


















