
在Go中,FileInfo.Mode().Perm() 仅返回标准的9位Unix权限(如0755),不包含SUID(4000)、SGID(2000)和Sticky(1000)等高3位特殊权限;需通过位运算结合os.ModeSetuid、os.ModeSetgid、os.ModeSticky常量手动提取。
在go中,`fileinfo.mode().perm()` 仅返回标准的9位unix权限(如0755),不包含suid(4000)、sgid(2000)和sticky(1000)等高3位特殊权限;需通过位运算结合`os.modesetuid`、`os.modesetgid`、`os.modesticky`常量手动提取。
Go语言的os.FileMode类型实际使用12位整数表示文件权限与属性,其中低9位对应经典的rwxr-xr-x(即0777掩码),而高3位则分别表示特殊权限标志:
- os.ModeSetuid(0x800,即十进制2048,八进制4000)
- os.ModeSetgid(0x400,即十进制1024,八进制2000)
- os.ModeSticky(0x200,即十进制512,八进制1000)
FileInfo.Mode().Perm() 方法内部执行了 m & 0777 掩码操作,因此自动屏蔽了高3位——这正是调用chmod 4755后却只看到0755的原因。
✅ 正确获取完整权限模式的推荐做法如下:
package main
import (
"fmt"
"os"
)
func main() {
fi, err := os.Stat("example.bin")
if err != nil {
panic(err)
}
mode := fi.Mode()
// 获取标准权限(低9位)
perm := mode.Perm() // e.g., 0755
// 检查特殊权限位
hasSetuid := mode&os.ModeSetuid != 0
hasSetgid := mode&os.ModeSetgid != 0
hasSticky := mode&os.ModeSticky != 0
// 组合成完整八进制权限字符串(如 "4755")
fullPerm := uint32(perm)
if hasSetuid {
fullPerm |= 04000
}
if hasSetgid {
fullPerm |= 02000
}
if hasSticky {
fullPerm |= 01000
}
fmt.Printf("Raw mode: 0%o\n", mode) // 例如:04755(含特殊位)
fmt.Printf("Perm(): 0%o\n", perm) // 仅:0755
fmt.Printf("Full octal: 0%o\n", fullPerm) // 显式构造:04755
fmt.Printf("SUID: %t, SGID: %t, Sticky: %t\n", hasSetuid, hasSetgid, hasSticky)
}⚠️ 注意事项:
立即学习“go语言免费学习笔记(深入)”;
- 不要依赖 fmt.Sprintf("%o", fi.Mode().Perm()) 来还原chmod设置的完整权限值,它永远缺失高3位;
- os.FileMode 还包含其他非权限位(如目录、符号链接、设备文件等标志),若需严格区分,应结合 mode.IsDir()、mode&os.ModeSymlink != 0 等判断;
- 在跨平台场景中,这些特殊权限位仅在Unix-like系统有效,Windows下无意义(os.ModeSetuid等恒为0)。
总结:Go的设计明确分离了“基础权限”与“文件类型/特殊属性”,Perm() 是语义明确的权限子集提取器,而非原始位拷贝。理解这一设计意图,才能正确解析4755、2755、1755等带特权位的权限模式。


















