Go无法通过os.Stat或os.IsPermission判断只读挂载,需解析/proc/mounts(Linux)或调用unix.Getfsstat(macOS)检查挂载选项是否含ro,Windows则无此概念。

Go 本身不感知挂载是否只读,所有写操作失败都表现为 permission denied 错误;关键在于提前检测、区分错误类型,并避免在只读路径上执行 os.Create、os.WriteFile 或 os.Mkdir 等写入行为。
如何判断某个路径是否位于只读挂载点上
不能靠 os.Stat 或 os.IsPermission 判断——它们只反映文件/目录自身的权限位,不体现挂载选项。正确做法是解析 /proc/mounts(Linux)或调用 unix.Getfsstat(macOS),匹配挂载点后检查 options 字段是否含 ro:
- Linux 下:打开
/proc/mounts,逐行strings.Fields(line),取第 4 项(options 列),再用strings.Contains(opts, "ro") - macOS 下:
unix.Getfsstat返回的unix.Statfs_t中无直接 ro 标志,需结合FSTYPENAME和挂载行为推断(如cdrom、ntfs常为只读) - Windows 不支持挂载选项语义,
ro概念不存在,只看文件是否设为只读属性(os.Chmod(path, 0444))
为什么 os.OpenFile(..., os.O_CREATE|os.O_WRONLY) 在只读挂载上会报 no such file or directory
这不是路径问题,而是内核在只读文件系统上拒绝创建新 inode 的表现。错误类型仍是 *os.PathError,但 Err 字段是 syscall.EROFS(只读文件系统),不是 syscall.ENOENT。常见误判点:
- 把
open /mnt/ro/file: permission denied当成权限不足(缺 x 位),实际是EROFS - 没检查
err的具体值,仅用os.IsNotExist(err)或os.IsPermission(err)分支处理,漏掉syscall.Errno == syscall.EROFS - 在容器中挂载
tmpfs并设ro,但忘记mount -o remount,ro后,/proc/mounts仍显示rw——必须以挂载时真实选项为准
写操作前必须做的三步预检
避免运行时 panic 或静默失败,任何可能写入路径的操作前都应顺序执行:
立即学习“go语言免费学习笔记(深入)”;
- 调用
os.Stat(path)确认路径存在且可访问;若失败,先区分是os.IsNotExist还是os.IsPermission - 用前述方法查
/proc/mounts,确认该路径所在挂载点是否含ro;注意符号链接会被自动解析,所以传给os.Stat的路径就是最终挂载点路径 - 若目标是创建文件或目录,额外检查父目录是否可写:
os.Stat(filepath.Dir(path))+info.Mode().Perm() & 0200 != 0(所有者有写位);只读挂载下,父目录即使权限是0777,os.Mkdir仍会失败
真正麻烦的是嵌套挂载(如 overlayfs、bind mount),/proc/mounts 可能列出多个层级,而 os.Stat 返回的 st_dev 只指向最底层设备。这时必须按路径最长前缀匹配挂载点,而非简单字符串相等。


















