
在 Go 的 Plan 9 平台支持中,Stat_t 并未以传统 Unix 风格定义;其功能由 *syscall.Dir 类型承担,该类型直接对应 9P 协议的 stat 消息解码结果,并通过 os.FileInfo.Sys() 方法暴露。
在 go 的 plan 9 平台支持中,`stat_t` 并未以传统 unix 风格定义;其功能由 `*syscall.dir` 类型承担,该类型直接对应 9p 协议的 stat 消息解码结果,并通过 `os.fileinfo.sys()` 方法暴露。
Go 标准库对 Plan 9 的系统调用抽象与 Unix/Linux/macOS 等平台显著不同:它不使用 struct stat 或 Stat_t 这类 C 风格的固定内存布局结构,而是基于 9P 文件协议的语义,采用动态解析方式处理文件元数据。核心机制如下:
- 调用 os.Stat(path) 时,最终进入 os.stat_plan9.go 中的 dirstat 函数;
- dirstat 内部调用 syscall.Stat(buf []byte),该函数向内核发起 stat 系统调用,并将原始二进制 9P stat 消息写入提供的字节缓冲区;
- 接着,syscall.UnmarshalDir(buf) 被调用来解析该缓冲区——它严格遵循 9P 协议规范(参见 Plan 9 Programmer’s Manual, Section 5),将变长字段(如名字、权限、UID/GID、长度、修改时间等)解包为 Go 结构体;
- 解包结果即为 *syscall.Dir 类型,其定义位于 src/syscall/dir_plan9.go,包含字段如 Name, Qid, Mode, Length, Mtime, Uid, Gid, Muid 等。
// 示例:获取并检查 *syscall.Dir 实例
fi, err := os.Stat("/bin/rc")
if err != nil {
log.Fatal(err)
}
if sys := fi.Sys(); sys != nil {
if dir, ok := sys.(*syscall.Dir); ok {
fmt.Printf("Name: %s, Mode: 0%o, Size: %d, Mtime: %d\n",
dir.Name, dir.Mode, dir.Length, dir.Mtime)
}
}
⚠️ 注意事项:
- *syscall.Dir 是 Plan 9 特有的运行时解析结果,不可跨平台使用;在其他 GOOS 下 fi.Sys() 返回类型完全不同(如 *syscall.Stat_t 或 *syscall.Win32FileAttributeData);
- syscall.Dir 字段值为原始协议字段,未做额外标准化(例如 Mode 直接映射 9P 的 d.mode,非 POSIX 权限位);
- 若需可移植元数据操作,请始终通过 os.FileInfo 接口方法(如 fi.Name(), fi.Size(), fi.Mode())访问,而非依赖 Sys() 返回值。
综上,Plan 9 下没有 Stat_t,但有更契合其设计哲学的 *syscall.Dir —— 它不是编译期静态结构,而是运行时从 9P 消息动态构建的协议感知对象,体现了 Go 对不同操作系统抽象层的精准适配。











