问题描述:

今天学习 Golang 文件操作实践时,当我创建一个文件(夹)出现文件权限与我代码设置不一致的问题

以下为我创建文件夹的代码:

1
2
3
4
5
6
func main() {
err := os.MkdirAll("g10guang/t1/t2", 0666)
if err != nil {
       fmt.Println(err)
   }
}

output:

mkdir g10guang/t1: permission denied

g10guang 文件夹创建成功,可是下面的 t1 文件夹创建失败

通过 ls -l 命令查看 g10guang 文件夹信息

drw-rw-r-- 2 g10guang g10guang 4096 Feb  8 13:23 g10guang

Linux 权限

其实我们创建文件夹、文件时候都是经过 Linux 系统调用完成的,所以这是 Linux 创建文件时候会把用户指定的权限 减去 umask,而我本地 umask 为 002。通过 umask 命令查看 umask

分析

通过 g10guang 用户运行代码,文件夹当然所属于 g10guang

尝试 cd g10guang,出现错误,错误信息:cd: permission denied: g10guang

文件夹是属于我的,我怎么不能够 cd 呢?

原因是:需要 cd 到一个文件夹,那么必须要有当前文件夹的执行权限 x,Linux 下设计一切皆文件,文件夹也是一个特殊的文件

如果使用 os.MkdirAll 方法创建文件夹时,必须基于文件夹所有者 x 执行权限以及 w 写权限,为什么需要写权限,可以通过 vim 去打开一个文件夹,可以看到文件夹里的信息(记得吗,文件夹也是文件),比如我一个文件夹通过 vim 打开的信息:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
" ============================================================================
" Netrw Directory Listing                                        (netrw v155)
"   /home/g10guang/Templates/blog
"   Sorted by      name
"   Sort sequence: [\/]$,\<core\%(\.\d\+\)\=\>,\.h$,\.c$,\.cpp$,\~\=\*$,*,\.o$,\.obj$,\.info$,\.swp$,\.ba
"   Quick Help: <F1>:help  -:go up dir  D:delete  R:rename  s:sort-by  x:special
" ==============================================================================
../
./
.git/
.sass-cache/
_posts/
_site/
g10guang.github.io/
.gitignore
.gitmodules
404.html
Gemfile
Gemfile.lock
_config.yml
about.md
index.md

文件夹中记录着里面有哪些文件以及文件夹,其中 xxx// 结尾的是文件夹,其他的是文件,所以在文件夹中创建一个文件夹需要改变文件夹信息,需要有写文件夹的权限

创建指定权限文件方法

两种方法:

  1. 改变 umask 后再创建文件,其后再把 umask 改为原来的 umask

  2. 先创建文件,然后再改变文件的权限

方法一

改变 umask 后再创建文件,其后再把 umask 改为原来的 umask

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import (
"os"
"fmt"
"syscall"
)

func main() {
mask := syscall.Umask(0)    // 改为 0000 八进制
defer syscall.Umask(mask)   // 改为原来的 umask
err := os.MkdirAll("g10guang/t1/t2", 0766)
if err != nil {
       fmt.Println(err)
   }
}

方法二

先创建文件,然后再改变文件的权限

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import (
"os"
"fmt"
)

func main() {
err := os.MkdirAll("g10guang/t1/t2", 0777)
if err != nil {
       fmt.Println(err)
   }
   os.Chmod("g10guang", 0777)
   os.Chmod("g10guang/t1", 0777)
   os.Chmod("g10guang/t1/t2", 0777)
}

golang 还不支持递归更改多个文件夹的权限,所有需要一个一个调用。

总结

Linux 文件操作都是调用 Linux 的系统调用完成的,虽然 Pythonjava 等创建一个文件不会让显示让编程人员指定所创建的文件的权限,但是 Golang 需要,所以我们编程还是需要了解一点内核知识.

转载:https://zhuanlan.zhihu.com/p/33692995