
go 中 `os.mkdir()` 创建目录的实际权限 = 指定权限 &^ umask,因此即使传入 `0777`,也会被系统 umask(如 `0022`)过滤掉部分位,导致权限低于预期。
在 Go 程序中使用 os.Mkdir(path, perm) 创建目录时,传入的 perm 参数(如 0777)并非最终生效的文件系统权限,而是会与当前进程的 umask 值进行按位取反后与运算(即 perm &^ umask)。这是 Unix/Linux 系统的通用行为,Go 完全遵循该语义。
以你的示例为例:
err := os.Mkdir("/var/run/testdir", 0777)若当前进程 umask 为 0022(常见默认值),则实际创建权限为:
0777 &^ 0022 = 0755 → 对应 drwxr-xr-x,这正是你观察到的结果(所有者可读写执行,组和其他用户仅可读执行)。
✅ 验证当前 umask(Linux/macOS 终端):
umask # 输出通常为 0022 或 0002
✅ 临时绕过 umask 限制(不推荐生产环境):
可通过 syscall.Umask() 临时修改进程 umask(需 import "syscall"),但注意该操作是全局且非线程安全的,且可能影响其他 goroutine 或后续系统调用:
package main
import (
"fmt"
"os"
"syscall"
)
func main() {
// 保存原始 umask
oldUmask := syscall.Umask(0) // 设为 0,禁用掩码
defer syscall.Umask(oldUmask) // 恢复
err := os.Mkdir("/var/run/testdir", 0777)
if err != nil {
fmt.Printf("failed to create dir: %v\n", err)
return
}
fmt.Println("Directory created with full 0777 permissions")
}⚠️ 更安全、推荐的实践方式:
使用 os.MkdirAll() + os.Chmod() 显式设置最终权限(原子性稍弱,但在绝大多数场景下足够可靠且清晰):
package main
import (
"fmt"
"os"
)
func mkdirWithExactPerm(path string, perm os.FileMode) error {
// 先创建目录(允许父目录不存在)
if err := os.MkdirAll(path, 0755); err != nil {
return err
}
// 再精确设置权限(覆盖 umask 影响)
return os.Chmod(path, perm)
}
func main() {
if err := mkdirWithExactPerm("/var/run/testdir", 0777); err != nil {
fmt.Printf("error: %v\n", err)
return
}
fmt.Println("Directory created with exact 0777 permissions")
}? 关键注意事项:
- os.Mkdir() 和 os.MkdirAll() 的 perm 参数均受 umask 影响,无例外;
- 0777 是八进制字面量,Go 中必须写作 0777(而非 777 或 "777");
- 在 /var/run/ 等需 root 权限的路径下操作时,确保程序以足够权限运行(如 sudo),否则 Mkdir 本身会因权限不足失败;
- 若需严格保证权限(如安全敏感服务),建议创建后调用 os.Stat() 验证 os.FileInfo.Mode() 是否符合预期。
总之,理解 umask 是掌握 Go 文件权限控制的关键前提——它不是 Go 的“bug”,而是操作系统级的安全机制;合理组合 MkdirAll 与 Chmod,即可在保持安全性的同时实现精准权限管理。










