os.ispermission是唯一靠谱的权限判断方式,它穿透多层错误包装准确识别syscall.eacces或error_access_denied,必须传原始err且不可用err==os.errpermission;os.stat失败后需先errors.is(err, fs.errnotexist)判不存在,再os.ispermission判权限拒绝。

os.IsPermission 是唯一靠谱的权限判断方式
权限不足不是 Go 的 bug,是操作系统在拦你——别用字符串匹配错误信息,也别指望 Go 自动提权。os.IsPermission 就是专为这种场景设计的:它穿透多层错误包装(比如 *os.PathError 或 *fmt.wrapError),准确识别底层是否为 syscall.EACCES(Linux/macOS)或 ERROR_ACCESS_DENIED(Windows)。
必须传入原始 err,不能先用 fmt.Errorf("failed: %w", err) 包一层再传,否则会丢失底层错误类型;也别写 err == os.ErrPermission——这几乎永远为 false,因为实际错误是 *os.PathError 实例,不是那个预定义变量。
-
os.IsPermission和errors.Is(err, fs.ErrPermission)效果一致,但语义更明确,推荐在权限检查场景优先使用 - 它只对权限类错误返回
true;磁盘满、路径过长、软链循环等都返回false,别误以为它是通用错误分类器 - 常见错误现象如
open /etc/shadow: permission denied或mkdir /root/mydir: permission denied,都适用该判断
os.Stat 后怎么区分“不存在”和“存在但没权限”
os.Stat 失败不等于路径不存在。它可能因权限不足、符号链接循环、设备忙等多种原因失败。关键是要分两步判断:
- 先用
errors.Is(err, fs.ErrNotExist)确认是否真不存在——这是 “not found” 的唯一可靠依据 - 如果不是
fs.ErrNotExist,再用os.IsPermission(err)判断是否因权限被拒——此时路径物理上存在,只是你无法读取元信息(比如/root下的目录) - 其他情况如
syscall.ELOOP(软链循环)、syscall.ENOTDIR(中间某段是文件而非目录),都不该归为“不存在”,需单独处理
filepath.WalkDir 遇到权限错误默认跳过,怎么让它中断或收集
filepath.WalkDir 的回调函数返回非-nil error 时,行为由错误值决定:filepath.SkipDir 会跳过当前目录;其他任意 error 都会立即终止遍历。但它不会主动暴露错误类型,得你自己判断:
- 想中断:在回调里检测到权限错误(
os.IsPermission(err))就直接return err - 想收集:声明一个
[]error切片,在回调里把权限错误append进去,最后统一处理;注意别return错误,否则遍历提前结束 - 别依赖
os.IsPermission对所有错误都生效——它只对EACCES/EPERM/ERROR_ACCESS_DENIED有效
os.MkdirAll 权限受 umask 影响,别硬写 0755
os.MkdirAll(path, 0755) 在 Linux/macOS 上创建的目录最终权限 = 0755 &^ umask。比如系统 umask 是 0022,结果就是 0755 &^ 0022 = 0755;但若 umask 是 0002,结果就变成 0755 &^ 0002 = 0755(看起来一样),而如果目标是 0777,实际可能是 0775。
- 不要假设传入的 mode 就是最终权限;必要时用
os.Chmod补调一次 - 预检查父目录执行权限很重要:即使目标路径可写,若中间某级目录缺少
x权限(不可进入),os.MkdirAll仍会失败且报permission denied - 容器或 SELinux 环境下,即使权限数字正确,也可能被策略拦截,这时
os.IsPermission仍返回true,但需查系统日志确认真实原因
noexec、SELinux 策略、用户命名空间映射)耦合,os.IsPermission 能帮你准确定位“是权限问题”,但没法告诉你“为什么没权限”。golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











