go标准库的os.mkdir等函数仅处理os.filemode低9位权限,高位特殊权限位(如sticky、suid)会被截断,需用x/sys/unix系统调用显式设置。

Go 语言无法直接设置或读取 Linux 的 SetUID / SetGID / Sticky Bit 等特殊权限位(除非用 syscall),os.FileMode 的 0755 类写法只影响低 9 位,高比特位是目录/符号链接等类型标志,不是传统 Unix 特殊权限。
为什么 os.Mkdir("d", 01755) 不会设粘滞位
很多人试过在 perm 参数里写 01755(即八进制的四位数),以为能像 shell 的 chmod 1755 那样启用 sticky bit,但实际创建出来的目录权限仍是 0755 —— 因为 os.Mkdir 和 os.OpenFile 的 perm 参数只取低 9 位,高位被静默截断。
-
01755在 Go 中是整数值 1005(十进制),os.FileMode(01755)被当作一个完整 uint32,但系统调用(如 mkdirat)只提取其低 9 位:1005 & 0777 = 493 → 八进制0755 - 真正起作用的粘滞位(bit 01000)必须通过
syscall层显式传入,标准库不暴露该能力 -
os.ModeSticky是一个常量(值为01000),但它仅用于 判断(如fi.Mode() & os.ModeSticky != 0),不能直接参与创建时的权限拼接
想设 SetUID / Sticky Bit?只能 syscall
标准库绕不开权限截断,要写入第 10–12 位(SUID=04000、SGID=02000、Sticky=01000),必须调用底层系统调用。以创建带 sticky bit 的目录为例:
package main
import (
"golang.org/x/sys/unix"
"unsafe"
)
func MkdirWithSticky(name string, perm uint32) error {
// perm 应含 sticky 位,例如 01755
return unix.Mkdirat(unix.AT_FDCWD, name, perm)
}
- 注意:这里用的是
unix.Mkdirat(来自golang.org/x/sys/unix),不是os.Mkdir -
perm类型是uint32,直接传01755即可,不会被截断 - 同理,SetUID 用
04755,SetGID 用02755;多个标志可 | 组合,如04755 | 02000 - Windows 下这些位完全无效,代码需做平台判断(
build tag或runtime.GOOS == "linux")
os.Chmod 能否补上 sticky bit?
不能。和创建一样,os.Chmod 也只操作低 9 位 —— 它内部调用的仍是 fchmodat 系统调用,且传入的 mode 参数同样被掩码处理(mode & 0777)。
- 验证方式:
os.Chmod("d", 01755)后执行ls -ld d,你会发现t位没出现 - 正确做法:仍需
unix.Chmod("d", 01755)(来自x/sys/unix) - 注意:
unix.Chmod不检查文件是否存在,也不区分文件/目录,出错时返回EPERM或EROFS,需自行包裹错误处理
读取时如何识别特殊权限位
虽然写不进去,但 os.Stat 能正确读出已存在的特殊权限(只要文件系统支持且你有权限读 stat):
fi, _ := os.Stat("d")
mode := fi.Mode()
if mode&os.ModeSticky != 0 {
// 目录有 sticky bit
}
if mode&04000 != 0 {
// 有 setuid(注意:os.ModeSetuid 不存在,得手写 04000)
}
-
os.ModeSticky存在,但os.ModeSetuid和os.ModeSetgid不存在 —— 标准库只定义了类型标志(ModeDir,ModeSymlink),没定义 SUID/SGID 这类权限标志 - 所以判断 setuid 得写
mode & 04000 != 0,不能依赖未定义常量 -
fi.Mode().Perm()仍只返回低 9 位(即mode & 0777),特殊位需单独与对应掩码 & 判断
真正难的不是“怎么写”,而是意识到 Go 标准库对 Unix 权限做了有意的简化抽象 —— 它把“文件类型”和“访问权限”混在一个 FileMode 里,却把“特殊执行位”排除在抽象之外。一旦需要它们,就得跨过 os 包,直面 syscall。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











