os.OpenFile 的 flag 和 perm 参数作用不同:perm 仅在 flag 含 os.O_CREATE 时生效,且受 umask 影响;Windows 下 perm 被忽略;跨平台安全需显式 chmod 或平台适配。
很多人误以为 os.OpenFile 的第三个参数 perm(权限位)在所有情况下都生效——其实它只在 flag 包含 os.O_CREATE 时才起作用,且仅用于新建文件。如果文件已存在,perm 完全被忽略,系统也不会修改已有文件的权限。
os.OpenFile("data.txt", os.O_RDWR|os.O_CREATE, 0600):文件不存在时创建,权限为 0600(仅属主可读写)os.OpenFile("data.txt", os.O_RDWR, 0600):无论 perm 值是多少,只要文件存在,就只打开,不改权限os.O_CREATE,传任何 perm 都无效,Go 甚至可能静默忽略(无 panic,但无效果)Go 中的 perm 是八进制字面量,对应 POSIX 的 mode_t,但注意:它不包含 setuid/setgid/sticky 位,且 Go 运行时会与进程 umask 按位与(AND)后再应用。也就是说,你写的 0600 最终权限可能是 0600 &^ umask。
0022,所以 0644 &^ 0022 == 0644,而 0600 &^ 0022 == 0600
0077(严格模式),0644 &^ 0077 == 0600,此时即使你传 0644,实际也是 0600
os.Chmod 后置修正(见下一点)如果业务要求文件权限必须严格等于某值(比如密钥文件必须是 0600,哪怕 umask 是 0002),唯一可靠方式是先创建再显式 os.Chmod:
f, err := os.OpenFile("secret.key", os.O_CREATE|os.O_WRONLY, 0600)if err != nil { return err}if err = f.Close(); err != nil { return err}// 强制设为 0600,无视 umaskreturn os.Chmod("secret.key", 0600)
os.Chmod,否则在某些文件系统(如 NFS)上可能失败os.OpenFile 返回的 *os.File 上调用 Chmod(f.Chmod 不存在),要用路径字符串调用 os.Chmod
os.Rename,再 Chmod
Go 的 os.OpenFile 在 Windows 下对 perm 参数不做任何处理,既不报错也不生效。文件权限由 ACL 控制,Go 标准库不暴露 ACL 设置接口。这意味着跨平台代码中依赖 perm 实现安全控制是危险的。
0600 能限制其他用户访问;Windows 上同名文件可能被任意用户打开(取决于父目录 ACL)golang.org/x/sys/windows 调用 SetNamedSecurityInfo,但这属于特权操作,常需管理员权限