
go 使用 os.mkdir() 创建目录时,实际权限 = 指定权限 &^ umask,因此即使传入 0777,也可能因系统 umask(如 0022)导致权限被屏蔽,最终得到 drwxr-xr-x 等“缩水”权限。
在 Go 中,os.Mkdir(path, perm) 的第二个参数 perm 并非直接设置最终文件系统权限,而是与进程当前 umask 进行按位与非(bitwise AND NOT)运算后的结果。这是 Unix/Linux 系统级行为,Go 完全遵循 POSIX 语义。
例如,你传入 0777(即十进制 511),若当前进程 umask 为 0022(常见默认值),则实际创建权限为:
0777 &^ 0022 → 0755 → drwxr-xr-x
这正是你观察到 drwxr-xr-x 的根本原因——组和其他用户的写权限(w)被 umask 屏蔽了。
✅ 正确做法:使用 os.MkdirAll() + 显式 chmod(推荐)
若需确保目录拥有精确权限(如 0777),应分两步操作:
package main
import (
"fmt"
"os"
)
func main() {
dir := "/var/run/testdir"
// 1. 创建目录(使用宽松权限占位,避免 umask 干扰逻辑)
err := os.Mkdir(dir, 0755)
if err != nil && !os.IsExist(err) {
fmt.Printf("failed to create dir: %v\n", err)
return
}
// 2. 强制设置目标权限(绕过 umask 影响)
err = os.Chmod(dir, 0777)
if err != nil {
fmt.Printf("failed to chmod dir: %v\n", err)
return
}
fmt.Println("Directory created with 0777 permissions")
}⚠️ 注意事项: os.Chmod() 仅修改权限位,不改变所有者/所属组;确保运行程序具有足够权限(如 root 对 /var/run/ 下目录)。 若需递归创建多级路径(如 /var/run/testdir/sub),请改用 os.MkdirAll(dir, 0755) 配合后续 os.Chmod(),否则 os.Mkdir() 仅创建最后一级。 在容器或 systemd 服务中,umask 可能被显式配置(如 UMask=0002),可通过 syscall.Umask(0) 临时修改——但不推荐:该操作是全局且非线程安全的,可能影响其他 goroutine 或第三方库。
? 验证当前 umask(调试用)
可在程序中打印当前 umask(需导入 syscall):
import "syscall"
// ...
mask := syscall.Umask(0) // 获取并重置为 0(注意:会改变当前 umask!)
syscall.Umask(mask) // 立即恢复,仅用于读取
fmt.Printf("Current umask: %04o\n", mask)但生产代码中应避免依赖或修改 umask,而采用 Chmod 显式赋权这一清晰、可预测、符合最小权限原则的方式。
总之,理解 umask 是掌握 Go 文件权限行为的关键;而 Mkdir + Chmod 组合,是实现确定性权限控制最可靠、最符合工程实践的标准方案。










