go标准库不支持acl,仅提供基础unix权限;linux需用syscall操作xattr,windows需cgo调用winapi;跨平台无抽象层,推荐用github.com/djherbis/acl或外部命令兜底。

Go 里没有内置 ACL 支持
Go 标准库的 os 包只提供类 Unix 的基本权限(os.FileMode),也就是 rwx 三组三位的八进制模式,不支持 Windows 的 DACL/SACL,也不支持 Linux 的 POSIX ACL(如 setfacl/getfacl 对应的扩展属性)。这意味着你调用 os.Chmod 或 os.OpenFile 时传入的 0750,永远只影响传统权限位,对 user:alice:rwx 这类规则完全无感知。
常见错误现象:
• 在 Linux 上用 setfacl -m u:alice:rwx /tmp/test 设了 ACL,再用 Go 读 os.Stat,返回的 Mode() 仍显示 0755,且不会报错 —— 它根本没读 ACL;
• 误以为 os.Chmod(path, 0600) 能清除所有其他用户的访问权,实际上 ACL 条目依然生效,root 或特定用户仍可绕过。
- Linux 下 ACL 存储在扩展属性(xattr)中,需用
syscall.Getxattr+"system.posix_acl_access"手动读取,但跨内核版本不稳定 - Windows 下需调用
syscall.LookupAccountName、syscall.GetNamedSecurityInfo等 WinAPI,必须用cgo,且仅限 Windows 平台 - 跨平台抽象层(如
golang.org/x/sys/unix)目前不封装 ACL 操作 —— 它连getfacl的基础能力都没提供
Linux 上读写 POSIX ACL 的最小可行方案
如果你明确只要 Linux,且能接受 cgo 和 syscall 级操作,可以用 github.com/djherbis/acl 这个轻量库(它内部用 unix.Getxattr/unix.Setxattr 封装了 system.posix_acl_access)。它不依赖外部命令,也不 require root,但要求内核支持(2.6+ 基本都行)。
使用场景:部署工具需精确复现生产环境文件权限,包括 ACL;审计脚本要检查敏感目录是否被意外授予额外用户权限。
立即学习“go语言免费学习笔记(深入)”;
- 读 ACL:
acl.Get("/etc/ssl/private", acl.Access)返回[]acl.Entry,每个含Tag(如acl.USER)、ID(uid/gid)、Perms(r/w/x 位) - 写 ACL:
acl.Set(path, acl.Access, []acl.Entry{{Tag: acl.USER, ID: 1001, Perms: acl.READ | acl.WRITE}}),注意:会**覆盖**原有 ACL,不是追加 - 性能影响:每次调用触发两次系统调用(get/setxattr),比
os.Chmod慢一个数量级;频繁操作建议批量处理或缓存结果
Windows 上设置 DACL 必须用 cgo
Go 原生无法调用 Windows 安全 API。想给文件加“仅 Administrator 可读”,必须写 cgo 代码调用 SetNamedSecurityInfo。官方文档明确说:“Go 不提供对 Windows 访问控制列表 (ACL) 的直接支持”。
容易踩的坑:
• 忘记在 Go 文件顶部加 // #include <windows.h></windows.h> 和 import "C";
• 传入的 lpObjectName 是 Unicode 路径,需用 C.CString 转换,且必须手动 C.free;ERROR_INVALID_PARAMETER 错误大概率是路径编码或缓冲区长度问题。
- 典型流程:构造
EXPLICIT_ACCESS结构体 →SetEntriesInAcl生成新PACL→SetNamedSecurityInfo应用到文件 - 权限字符串如
"O:BAG:BAD:(A;;FR;;;BA)"(用SetSecurityInfo)虽可用,但解析难、调试难,不推荐直接拼 SDDL - 兼容性:Windows Server 2003+ 都支持,但 Vista 之前需额外链接
advapi32.lib,现代 Go 工具链已默认包含
替代思路:用外部命令兜底,但别信 stdout
如果项目允许执行 shell 命令,getfacl/setfacl(Linux)或 icacls(Windows)是最稳的路径。但别指望 exec.Command("getfacl", path).Output() 返回的结果能直接当结构体用 —— 输出格式随 locale 和版本浮动,getfacl 在不同发行版里字段顺序可能不同。
实操建议:
• Linux:用 getfacl -n path(数字 UID/GID)+ 正则提取 user:[0-9]+:[rwx-]+,比解析完整输出可靠;
• Windows:用 icacls path /save acl.txt /t 导出二进制不可读格式,改用 icacls path /grant *S-1-5-32-544:(R) 直接设 SID,避免中文组名乱码;
• 错误处理必须检查 cmd.Run() 返回的 *exec.ExitError,icacls 即使成功也常返回非零 exit code。
真正复杂的是权限继承与传播逻辑 —— 比如子目录是否自动继承父目录 ACL?setfacl -d 设置默认 ACL 后,新建文件权限怎么算?这些规则由内核/VFS 层实现,Go 层连表面都碰不到,只能靠测试验证行为。










