go创建文件/文件夹时的权限问题

go 创建文件夹或者文件的时候,有点”反常识“,所见非所得

原本还以为发现了不得了的bug,结果,又是没好好看文档
如下的程序,创建多级文件夹

1
2
3
4
5
func main() {  
_ = os.MkdirAll("/tmp/prem/", 0777)

_, _ = os.Create("/tmp/file")
}

实际创建结果表面,默认0666的文件,实际为0644。而设置权限为0777的文件夹实际为0755

1
2
3
4
5
6
7
$ ll /tmp
total 160K
drwxr-xr-x 3 root root 4.0K Dec 15 2020 apollo
-rw-r--r-- 1 user user 0 Dec 17 15:30 file
drwx------ 2 root root 4.0K Sep 18 2020 go-build080350710
drwxr-xr-x 2 user user 4.0K Dec 17 15:25 prem
...

原因

方法注释中都已经写明白了,重点都是(before umask),看源码
Linux umask命令指定在建立文件时预设的权限掩码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// src/os/file.go
// Create creates or truncates the named file. If the file already exists,
// it is truncated. If the file does not exist, it is created with mode 0666
// (before umask). If successful, methods on the returned File can
// be used for I/O; the associated file descriptor has mode O_RDWR.
// If there is an error, it will be of type *PathError.
func Create(name string) (*File, error) {
return OpenFile(name, O_RDWR|O_CREATE|O_TRUNC, 0666)
}

// src/os/path.go
// MkdirAll creates a directory named path,
// along with any necessary parents, and returns nil,
// or else returns an error.
// The permission bits perm (before umask) are used for all
// directories that MkdirAll creates.
// If path is already a directory, MkdirAll does nothing
// and returns nil.
func MkdirAll(path string, perm FileMode) error {...}

再看系统中的umask,都对上了

1
2
$ umask
022

解决方法

修改umask

1
2
3
4
// 先将umask设置为0,即不会再减去默认的022
mask := syscall.Umask(0)
// 恢复
defer syscall.Umask(mask)

注意:syscall.Umask在Windows系统下是不可用的

先创建,再修改权限

1
2
// 并不支持递归修改权限,如果是多级目录,一级一级修改吧
os.Chmod("/tmp/prem/", 0777)

参考链接

原文链接
umask