Linuxのディレクトリにおける各パーミッションの役割

最近会社で聞かれて答えたことをまとめてみました。

owner/group/otherとか0777とかビット計算の話ではありません。ディレクトリにおけるrwxのそれぞれの役割についての話です。

# 確認環境
今回は[Lubuntu 18.04.1](https://lubuntu.me/downloads/)で確認しています。

とりあえずディレクトリとファイルを作ります。

```
lubuntu@lubuntu:~$ cd ~
lubuntu@lubuntu:~$ mkdir -p sandbox
lubuntu@lubuntu:~$ cd sandbox
lubuntu@lubuntu:~/sandbox$ mkdir -p d01/d02/d03
lubuntu@lubuntu:~/sandbox$ echo xxx > f01
lubuntu@lubuntu:~/sandbox$ touch d01/f02 d01/d02/f03 d01/d02/d03/f04
lubuntu@lubuntu:~/sandbox$ find d01 -type f | xargs -n 1 -I [] cp -p f01 []
lubuntu@lubuntu:~/sandbox$ tree
.
├── d01
│   ├── d02
│   │   ├── d03
│   │   │   └── f04
│   │   └── f03
│   └── f02
└── f01

3 directories, 4 files
lubuntu@lubuntu:~/sandbox$ ls -lR
.:
total 4
drwxrwxr-x 3 lubuntu lubuntu 80  3月 20 00:00 d01
-rw-rw-r-- 1 lubuntu lubuntu  4  3月 20 00:00 f01

./d01:
total 4
drwxrwxr-x 3 lubuntu lubuntu 80  3月 20 00:00 d02
-rw-rw-r-- 1 lubuntu lubuntu  4  3月 20 00:00 f02

./d01/d02:
total 4
drwxrwxr-x 2 lubuntu lubuntu 60  3月 20 00:00 d03
-rw-rw-r-- 1 lubuntu lubuntu  4  3月 20 00:00 f03

./d01/d02/d03:
total 4
-rw-rw-r-- 1 lubuntu lubuntu 4  3月 20 00:00 f04
lubuntu@lubuntu:~/sandbox$

```

# ディレクトリのReadパーミッション
d02のReadパーミッションを落としてみます。

```
lubuntu@lubuntu:~/sandbox$ chmod a-r d01/d02
lubuntu@lubuntu:~/sandbox$
```

ツリー表示はこんな感じになります。

```
lubuntu@lubuntu:~/sandbox$ tree
.
├── d01
│   ├── d02 [error opening dir]
│   └── f02
└── f01

2 directories, 2 files
lubuntu@lubuntu:~/sandbox$
```

ls表示はこんな感じになります。

```
lubuntu@lubuntu:~/sandbox$ ls -lR
.:
total 4
drwxrwxr-x 3 lubuntu lubuntu 80  3月 20 00:00 d01
-rw-rw-r-- 1 lubuntu lubuntu  4  3月 20 00:00 f01

./d01:
total 4
d-wx-wx--x 3 lubuntu lubuntu 80  3月 20 00:00 d02
-rw-rw-r-- 1 lubuntu lubuntu  4  3月 20 00:00 f02
ls: cannot open directory './d01/d02': Permission denied
lubuntu@lubuntu:~/sandbox$
```

d02が見えなくなるのはもちろん、d03やf03、d03配下のf04も見えなくなります。d02配下ではタブ補完もできなくなります。

さて、d02は見えなくなりました。しかしd03の存在を知っています。d03を直撃でツリー表示してみると、どうなるでしょうか？

```
lubuntu@lubuntu:~/sandbox$ tree d01/d02/d03
d01/d02/d03
└── f04

0 directories, 1 file
lubuntu@lubuntu:~/sandbox$
```

実はd03やf04を見ることができます。d02のReadパーミッションは、d02のディレクトリエントリ、d02の下にどのようなディレクトリやファイルがぶら下がっているかという情報を読み込む権限です。d03やf04を直撃で参照する際にはd02のディレクトリエントリを使用しないため、パーミッションの影響を受けません。

もちろん、f03やf04の内容を読むこともできます。

```
lubuntu@lubuntu:~/sandbox$ ls -l d01/d02/{f03,d03/f04}
-rw-rw-r-- 1 lubuntu lubuntu 4  3月 20 00:00 d01/d02/d03/f04
-rw-rw-r-- 1 lubuntu lubuntu 4  3月 20 00:00 d01/d02/f03
lubuntu@lubuntu:~/sandbox$ grep xxx d01/d02/{f03,d03/f04}
d01/d02/f03:xxx
d01/d02/d03/f04:xxx
lubuntu@lubuntu:~/sandbox$
```

# ディレクトリのWriteパーミッション
元通りの環境に戻した後、d02のWriteパーミッションを落としてみます。

```
lubuntu@lubuntu:~/sandbox$ chmod a-w d01/d02
lubuntu@lubuntu:~/sandbox$
```

d02にはファイルやディレクトリを作成できなくなりました。他のフォルダからd02にファイルを移動することもできません。

```
lubuntu@lubuntu:~/sandbox$ mkdir d01/d02/new_folder
mkdir: cannot create directory ‘d01/d02/new_folder’: Permission denied
lubuntu@lubuntu:~/sandbox$ touch d01/d02/new_file
touch: cannot touch 'd01/d02/new_file': Permission denied
lubuntu@lubuntu:~/sandbox$ mv f01 d01/d02
mv: cannot move 'f01' to 'd01/d02/f01': Permission denied
lubuntu@lubuntu:~/sandbox$
```

d02配下のファイルを移動することもできません。

```
lubuntu@lubuntu:~/sandbox$ mv d01/d02/f03 d01/d02/f03_new
mv: cannot move 'd01/d02/f03' to 'd01/d02/f03_new': Permission denied
lubuntu@lubuntu:~/sandbox$ mv d01/d02/f03 d01/d02/d03/
mv: cannot move 'd01/d02/f03' to 'd01/d02/d03/f03': Permission denied
lubuntu@lubuntu:~/sandbox$
```

d02のWriteパーミッションは、d02のディレクトリエントリ、d02の下にどのようなディレクトリやファイルがぶら下がっているかという情報を書き換える権限です。そのため、ファイル名を書き換える操作、ファイル名を追加削除する操作はできなくなります。

d02のディレクトリエントリを書き換えない操作であれば、パーミッションの影響を受けません。例えば、f03の内容を書き換えることは可能です。

```
lubuntu@lubuntu:~/sandbox$ echo xxx > d01/d02/f03
lubuntu@lubuntu:~/sandbox$ cat d01/d02/f03
xxx
lubuntu@lubuntu:~/sandbox$ echo yyy > d01/d02/f03
lubuntu@lubuntu:~/sandbox$ cat d01/d02/f03
yyy
lubuntu@lubuntu:~/sandbox$ 
```

同じ理由で、d03にはファイルやディレクトリを作成できます。

```
lubuntu@lubuntu:~/sandbox$ mkdir d01/d02/d03/new_folder
lubuntu@lubuntu:~/sandbox$ touch d01/d02/d03/new_file
lubuntu@lubuntu:~/sandbox$ tree
.
├── d01
│   ├── d02
│   │   ├── d03
│   │   │   ├── f04
│   │   │   ├── new_file
│   │   │   └── new_folder
│   │   └── f03
│   └── f02
└── f01

4 directories, 5 files
lubuntu@lubuntu:~/sandbox$
```

もっとも、この動きは一般ユーザーのホームディレクトリと同じですので、理解しやすいでしょう。ホームディレクトリの親ディレクトリ /home への書き込み権限はありません。しかし、ホームディレクトリ以下にはファイルを作成できます。それは、ディレクトリ /home のディレクトリエントリを書き換えるわけではないからです。

```
lubuntu@lubuntu:~/sandbox$ ls -ld / /home /home/lubuntu
drwxr-xr-x  1 root    root    260  3月 20 00:00 /
drwxr-xr-x  1 root    root     60  3月 20 00:00 /home
drwxr-xr-x 19 lubuntu lubuntu 500  3月 20 00:00 /home/lubuntu
lubuntu@lubuntu:~/sandbox$
```

ちなみに、以下の操作は不可です。一時ファイルに書き込んだ後、ファイルを差し替える際にd02のディレクトリエントリを書き換えようとして、エラーになります。

```
lubuntu@lubuntu:~/sandbox$ perl -pi -e 's/xxx/yyy/' d01/d02/f03
Can't remove d01/d02/f03: Permission denied, skipping file.
lubuntu@lubuntu:~/sandbox$
```

# ディレクトリのExecuteパーミッション
元通りの環境に戻した後、d02のExecuteパーミッションを落としてみます。

```
lubuntu@lubuntu:~/sandbox$ chmod a-x d01/d02
lubuntu@lubuntu:~/sandbox$
```

ツリー表示はこんな感じになります。

```
lubuntu@lubuntu:~/sandbox$ tree
.
├── d01
│   ├── d02
│   └── f02
└── f01
2 directories, 2 files
lubuntu@lubuntu:~/sandbox$
```

d02のReadパーミッションを落とした時と似ています。しかし、"[error opening dir]"という表示はありません。

ls表示はこんな感じになります。

```
lubuntu@lubuntu:~/sandbox$ ls -lR
.:
total 4
drwxrwxr-x 3 lubuntu lubuntu 80  3月 20 00:00 d01
-rw-rw-r-- 1 lubuntu lubuntu  4  3月 20 00:00 f01

./d01:
total 4
drw-rw-r-- 3 lubuntu lubuntu 80  3月 20 00:00 d02
-rw-rw-r-- 1 lubuntu lubuntu  4  3月 20 00:00 f02

./d01/d02:
ls: cannot access './d01/d02/f03': Permission denied
ls: cannot access './d01/d02/d03': Permission denied
total 0
d????????? ? ? ? ?             ? d03
-????????? ? ? ? ?             ? f03
ls: cannot open directory './d01/d02/d03': Permission denied
lubuntu@lubuntu:~/sandbox$
```

d02のディレクトリエントリ、d02にどのようなファイルやディレクトリが含まれているかという情報を読むことはできています。Readパーミッションを落とした時には、この情報を読むことはできませんでした。

しかし、d03やf03の存在は検出できたものの、パーミッション情報やファイルサイズを取得できません。辛うじて、d03がディレクトリでf03がファイルということがわかるのみです。

d02のExecuteパーミッションは、d02からd3やf03へ横断（トラバーサル）してよいかを表す権限です。そして、パーミッション情報やファイルサイズはd3やf03自身が持っている情報です。そのため、d3やf03のパーミッション情報やファイルサイズを取得できなくなります。

d02からd03へ横断できなくなってしまうため、d03に含まれるf04の内容を直撃で参照することもできなくなります。

```
lubuntu@lubuntu:~/sandbox$ ls -l d01/d02/d03/f04
ls: cannot access 'd01/d02/d03/f04': Permission denied
lubuntu@lubuntu:~/sandbox$
```

# ディレクトリのReadパーミッションとExecuteパーミッションの違いを図解

ReadとExecuteの違いを理解するための図を作ってみました。
![パーミッション.png](https://qiita-image-store.s3.amazonaws.com/0/381550/be3238e1-abf9-d61c-0a43-2f57e8634b34.png)

Readが落ちていると、d02の中にどのような名前のファイルやディレクトリがあるか、わからなくなります。しかし、名前を事前に知っている場合、d03にアクセスすることは可能です。

Executeが落ちていると、d02の中にどのような名前のファイルやディレクトリがあるかはわかります。しかし、ファイルの実体や次のディレクトリエントリへの横断（トラバーサル）ができなくなります。そのため、名前を知っていても、d03にアクセスすることはできなくなります。また、ディレクトリパスの途中に横断できない箇所が一ヶ所でもあると、それより下のディレクトリには辿りつけず、一切アクセスできなくなります。

# 意図的に書かなかったこと
- Sticky Bitの説明は、毛色が違うので省きました。
- 技術的なことを考えると図の中にi-nodeを含めるべきですが、分かりやすさを優先するためにi-nodeのことは省きました。
- ファイルの属性には、パーミッション情報やファイルサイズ以外にもオーナーやグループなどがありますが省きました。

# 公開後の主な修正
- ファイル属性情報のありかについての説明を加えました。
- ディレクトリsandboxの作成部分に余計なコマンドが含まれていたので削除しました。
- 図の一部に誤りがありましたので、図を差し替えました。