Linuxファイルメタデータとノードテーブル構造

# ファイルメタデータとノードテーブル構造
## inode テーブル構造
+ Linuxシステムでは、すべてがファイルです
+ 各ファイルは、ファイルメタデータと具体的な内容の2つの部分に分かれています
+ あるファイルのメタデータとその具体的な内容データは、ディスクパーティション上で別々に保存されます
+ ファイルメタデータを保存する領域を inode といいます:
各ファイルには1つのinodeとn(n>=1)個のblockデータブロックがあり、inodeはファイルメタデータを、データブロックはファイルの具体的な内容データを保存します。

+ ディスクがフォーマットされる際、システムは自動的にディスクを2つの領域に分けます:
→　1つはinode領域（inode table）で、ファイルのinodeを保存するためのものです。
→　もう1つはデータ領域で、多数のblock（ブロック）に分けられ、ファイルの具体的な内容データを保存するためのものです。
+ 1つのディスクパーティションにいくつのinodeとblockがあるかは、システムによって自動的に決定され、ファイルシステム、ディスクパーティションのサイズ、データブロックのサイズによって異なります
+ 1つのディスクパーティションに保存できるファイルの数は、ファイルのサイズ、ディスクパーティションのサイズ、inodeの数によって決まります
+ inode番号は再利用可能で、ファイルを削除した後、そのinode番号は回収され、次に新しいファイルが使用するために保持されます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3515709/42da15b8-bd83-cffd-6f6b-441e188725e1.png)
## 各inodeテーブルレコードが保存する情報
- inode number（インデックスノード番号）
- ファイルタイプ
- 権限
- 所有者とグループ
- リンク数
- ファイルサイズ
- 各種タイムスタンプ
- 具体的なデータブロックへのポインタ
- ファイルに関するその他のデータ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3515709/e47e58ce-f412-0d7b-368c-547fc29d7827.png)
## inode に関するポインタとブロックサイズ
### ポインタのサイズは4バイト、ブロックサイズは4KBです
- ポインタのサイズとブロックのサイズは、OSのプラットフォームやファイルシステムによって異なります

### 直接ポインタ
- 直接ポインタが12個あり、直接具体的なデータブロックを指し示します
- もしブロックのサイズが4096バイト（4KB）ならば、直接ポインタは最大で48KBのファイルサイズをサポートできます

### 間接ポインタ
- 間接ポインタが1個あり、一つのデータブロックを指し示しますが、そのブロック上に保存されているのはデータではなくポインタです
- ブロックのサイズが4096バイト（4KB）、ポインタが4バイトの場合、そのブロックには1024個のブロックアドレス（4096 / 4 = 1024）を保存できます。それによって最大で4MBのデータサイズ（1024 * 4096）をサポートできます

### 二重間接ポインタ
- 二重間接ポインタが1個あり、一つのデータブロックを指し示しますが、そのブロック上に保存されているのもポインタです
- 同様に、ポインタが4バイトで、それぞれのブロックが1024個のブロックアドレスを保存できるため、結果的に4GBのデータサイズ（1024 * 1024 * 4096）をサポートできます

### 三重間接ポインタ
- 三重間接ポインタが1個あり、一つのデータブロックを指し示しますが、そのブロック上にもポインタが保存されています
- 同様に、各ブロックが1024個のブロックアドレスを保存できるため、その結果として最大で4TBのデータサイズ（1024 * 1024 * 1024 * 4096）をサポートできます

### 単一ファイルの最大容量
- 直接ポインタ x 12 + 間接ポインタ + 二重間接ポインタ + 三重間接ポインタ

### ディレクトリ
- ディレクトリは特殊なファイルで、ディレクトリファイルの内容はそのディレクトリ内のファイルリストとinode番号との関連を保存しています
- ファイルにはinode番号がリンクされています
- 人はファイル名を通してファイルを参照します
- ディレクトリは、その下にあるファイル名とファイルのinode番号の間のマッピングです
- 
### cp コマンドとinode
- cp コマンドで空いているinode番号を割り当て、inodeテーブルに新たなエントリを生成します
- ディレクトリ内に新しいディレクトリ項目を作成し、名前とinode番号を関連付けます
- データをコピーして新しいファイルを生成します

### rm コマンドとinode
- rm コマンドでリンク数を減らし、解放されたinode番号を再利用のために使用できるようにします
- 使用されていたデータブロックを空きリストに返します
- ディレクトリ項目を削除します
- データは直ちに削除されませんが、他のファイルがデータブロックを使用すると上書きされます

### mv コマンドとinode
- mv コマンドが同じファイルシステム内のソースとターゲットで使用される場合、新しいファイル名に対応する新しいディレクトリ項目を作成します
- 古いディレクトリ項目と古いファイル名に関連するものを削除します
- inodeテーブル（時間戳を除く）やディスク上のデータの位置には影響を与えません：データは移動されません
- ソースとターゲットが異なるファイルシステムにある場合、mvはcpとrmの組み合わせに相当します

### ファイルシステムのタイプを確認する例
```
[root@rocky86 ~]# df -Th
ファイルシステム タイプ サイズ 使用量  空き容量 使用% マウントポイント
devtmpfs        devtmpfs  864M     0       864M    0%   /dev
tmpfs           tmpfs     893M   9.3M     884M    2%   /run
tmpfs           tmpfs     893M     0       893M    0%   /sys/fs/cgroup
/dev/mapper/rl-root xfs 70G 6.3G 64G 9% /
/dev/mapper/rl-home xfs 127G 986M 126G 1% /home
/dev/sda1       xfs      1014M    255M    760M  26%   /boot
```

### 分区inodeを確認する例
```
[root@rocky86 ~]# df -i
ファイルシステム Inodes使用量 空き 使用% マウントポイント
devtmpfs      220937     400 220537  1% /dev
tmpfs         228529     777 227752  1% /run
tmpfs         228529      17 228512  1% /sys/fs/cgroup
/dev/mapper/rl-root 36700160 132203 36567957 1% /
/dev/mapper/rl-home 66568192   544 66567648 1% /home
/dev/sda1      524288     310 523978  1% /boot
```

### ファイルのinodeを確認する例
```
[root@rocky86 ~]# ll -i abc
202110723 -rw-r--r-- 1 root root 0 Jul 12 10:57 abc

[root@rocky86 ~]# ls -i abc
202110723 abc

[root@rocky86 ~]# stat abc
ファイル: 'abc'
サイズ: 0		ブロック数: 0          IO ブロック: 4096   通常の空のファイル
デバイス: fd00h/64768d	Inode: 202110723  リンク数: 1
アクセス: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
アクセス日時: 2022-07-12 10:57:38.036950767 +0800
修正日時: 2022-07-12 10:57:38.036950767 +0800
変更日時: 2022-07-12 10:57:38.036950767 +0800
作成日時: 2022-07-12 10:57:38.036950767 +0800
```

### inode番号が枯渇するとディスクが満杯になる
- 分区が大きくなるほど、使用可能なinode番号が多くなります。現在の分区にはいくつinode番号があるかということは、その分区にいくつファイルを作成できるかを意味します
- 現在の分区のinode番号が枯渇した場合、新しいファイルを作成することはできず、「デバイスに空き容量がありません (No space left on device)」というメッセージが表示されます
- 分区の空き容量が不足している場合も、新しいファイルを作成することはできず、やはり「デバイスに空き容量がありません (No space left on device)」と表示されます

### 大量の空ファイルを作成してinode番号を枯渇させる
```
echo test-{1..523977}.txt | xargs touch #大量の空ファイルを作成してinode番号を枯渇させる
cp /dev/zero /tmp/ #実際の大きなファイルを作成してディスクを満杯にする
df -i #ディスク分区のinode番号の使用状況を確認する
df -lh #ディスク分区の利用状況を確認する
```

- ディスクの分区にはまだ空き容量があるにもかかわらず、ファイルが不足していると警告される場合、それはinode番号が枯渇しているためです
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3515709/121e939b-41de-fc4b-0ed7-e4fe33cfa25a.png)

- inode番号のリソースはまだ残っていますが、ディスクのデータ領域が枯渇しているため、ファイルを作成することができません
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3515709/88efffea-c713-88ac-0dfe-11077548715a.png)


### 大きなファイルを削除する例
```
[root@rocky86 ~]# cat /dev/null > /var/log/huge.log
```

上記のコマンドによって、/var/log/huge.log の内容が削除されますが、実際にはファイルサイズは変わらず、内容が空になります。追加の情報が必要であれば、ご質問ください。

## ハードリンクについて

### ハードリンクの役割
ハードリンクの役割は、一つのファイルに複数の有効なパス名を設定することです。新たなファイルを作成してあるファイルのinodeに指向させることで、これら2つのファイルは互いにハードリンクになります。つまり、複数のファイル名が同一のinodeを指しているのがハードリンクの本質です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3515709/89530571-8aa8-1042-0d69-e0fc52325a7e.png)


### ハードリンクの特性
- ハードリンクを作成すると、該当ディレクトリの中に追加の記録項目が生成され、ファイルを参照します
- 同一のファイルシステム上で一つの物理ファイルに対応しています
- 各ディレクトリが同じinode番号を参照しています
- 作成時にリンク数が増加します
- ファイル削除時：rmコマンドはリンクカウントをデクリメントします。ファイルは存在していて、最低でも一つのリンク数が必要です。リンク数がゼロになった時、そのファイルは削除されます
- ドライブやパーティションを跨ぐことはできません
- ディレクトリに対してハードリンクを作成することはサポートされていません


```markdown
書式：ln filename linkname

例：
# `.` は現在のディレクトリを表すため、ディレクトリ自身の参照と、それによって表されるディレクトリ名の参照で2回の参照があります。
# `..` は親ディレクトリを指し、親ディレクトリ自身への引用が1回あるほか、親ディレクトリの`.`への引用が1回、子ディレクトリの`..`からの引用が1回で、合計で3回の引用があります。

[root@rocky86 dir1]# ll -ai
合計 0
67689561 drwxr-xr-x 2 root root 6 7月 12 14:50 .
1230057 drwxr-xr-x 3 root root 43 7月 12 12:05 ..
```

## シンボリックリンク（またはソフトリンク）
シンボリックリンクは、Windowsのショートカットに似ています。
ソフトリンクは独立したファイルを作り、そのファイルは目的のファイル名を指しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3515709/f83d53e8-3a9f-b69d-33a6-86944de7b689.png)


ソフトリンクの特徴:

- シンボリックリンクの内容は参照されるファイルの名前です
- ディレクトリに対してシンボリックリンクを作成することができます
- パーティションをまたがるファイルを実装することができます
- 参照されるもう一つのファイルのパスです。そのサイズは指すパスの文字列の長さであり、対象ファイルのinodeのリファレンスカウントを増減させません
- ソフトリンクは相対パスを使用する場合、元のファイルのパスに対して相対的であり、現在のディレクトリに対してではありません
- シンボリックリンク自体を削除しても、元のディレクトリの内容は削除されません
- 元のディレクトリのファイルを削除しても、リンクファイルは削除されません
```markdown
フォーマット： `ln -s filename linkname`

例: シンボリックリンクを見る
[root@rocky86 /]# ll /bin/sh
lrwxrwxrwx. 1 root root 4 4月 12 15:05 /bin/sh -> bash
[root@rocky86 /]# ll /bin
lrwxrwxrwx. 1 root root 7 10月 11 2021 /bin -> usr/bin
[root@rocky86 /]# readlink /bin/sh
bash
[root@rocky86 /]# readlink /bin
usr/bin

例: ディレクトリを横切るシンボリックリンクを作成する場合、ソースファイルは現在のパスではなく、ターゲットファイルのパスを基準にする必要があります。
# 間違い
[root@rocky86 /]# ln -sv abc /boot/abc.link
'/boot/abc.link' -> 'abc'
[root@rocky86 /]# ll /boot/abc.link
lrwxrwxrwx 1 root root 3 7月 12 15:08 /boot/abc.link -> abc

# 正しい
[root@rocky86 /]# ln -sv /root/abc /boot/abc.link2
'/boot/abc.link2' -> '/root/abc'
[root@rocky86 /]# ll /boot/abc.link2
lrwxrwxrwx 1 root root 9 7月 12 15:10 /boot/abc.link2 -> /root/abc

# 正しい
[root@rocky86 /]# ln -sv ../root/abc /boot/abc.link3
'/boot/abc.link3' -> '../root/abc'
[root@rocky86 /]# ll /boot/abc.link3
lrwxrwxrwx 1 root root 11 7月 12 15:12 /boot/abc.link3 -> ../root/abc

例: シンボリックリンクを削除する
[root@rocky86 0712]# ll
合計 0
drwxr-xr-x 2 root root 48 7月 12 15:17 dir1
lrwxrwxrwx 1 root root 5 7月 12 15:18 dir1.link -> dir1/
# これはリンクが指しているディレクトリを削除します。
[root@rocky86 0712]# rm -rf dir1.link/
# これはリンクファイルを削除します。
[root@rocky86 0712]# rm -rf dir1.link
```
## ハードリンクとシンボリックリンクの違いに

|          | ハードリンク             | シンボリックリンク             |
|----------|------------------------|-------------------------------|
| 本質     | 同一のファイルを指す        | 同一のファイルを指さない          |
| デバイス間 | 対応していない            | 対応している                  |
| inode    | 同じ                    | 異なる                      |
| リンク数  | ハードリンク作成で増加、削除で減少 | 作成や削除をしても変わらない     |
| ディレクトリ | 対応していない            | 対応している                  |
| 相対パス | オリジナルファイルのパスは現在作業中のディレクトリに対している | オリジナルファイルのパスはリンクファイルに対している |
| オリジナルファイルの削除 | リンク数が1減るがアクセス不影響   | リンクファイルがアクセスできなくなる |
| ファイルタイプ | オリジナルファイルと同一        | リンクファイルはオリジナルファイルとは無関係 |

ハードリンクとシンボリックリンクは、UnixおよびUnix系オペレーティングシステムでファイルを指すための2つの異なる方法です。どちらもファイルへのアクセスパスを提供する目的は同じですが、実装方法と特性には違いがあります。

### ハードリンク (Hard Link)：
- **本質**：ハードリンクはファイルシステムの中のinode（インデックスノード）を指しており、ハードリンクは元のファイルの別名であり、元のファイルと完全に等価です。
- **inode**：ハードリンクは元のファイルと同じinode番号を共有します。
- **リンク数**：新しいハードリンクを作成するたびにファイルのリンク数が増加します。ハードリンクを削除すると、リンク数が減少します。リンク数が0になったときだけ、ファイルの実際のデータがディスクから削除されます。
- **元のファイルを削除**：元のファイルを削除してもハードリンクの有効性には影響しません。なぜならハードリンクは元のファイルそのものだからです。
- **デバイス間**：ハードリンクは同一ファイルシステム内にしか作成できません。
- **ディレクトリへの対応**：ほとんどのシステムでは、ディレクトリへのハードリンクの作成を許可していません。
- **ファイルタイプ**：ハードリンクは、元のファイルの直接的なマッピングですので、ファイルタイプは常に元のファイルと同じです。

### シンボリックリンク (Symbolic Link)：
- **本質**：シンボリックリンクは、別のファイルやディレクトリへのパスを指すファイルのショートカットです。これは独立したファイルで、別のファイルやフォルダへのパスを指しています。
- **inode**：シンボリックリンクは独自のinode番号を持ち、元のファイルのinode番号とは異なります。
- **リンク数**：シンボリックリンクを作成または削除しても元のファイルのリンク数に影響しません。
- **元のファイルを削除**：シンボリックリンクが指している元のファイルが削除されると、リンクは破損します（ダングリングリンクになります）し、そのシンボリックリンクを通じて元のデータにアクセスすることはできません。
- **デバイス間**：シンボリックリンクはファイルシステムを越えて作成できます。
- **ディレクトリへの対応**：シンボリックリンクはディレクトリを指すことができます。
- **ファイルタイプ**：シンボリックリンク自体は特別なタイプのファイルであり、含まれているのは別のファイルまたはフォルダへのパスであり、元のファイルのタイプとは無関係です。
- **相対パス**：シンボリックリンクは相対パスを使用できます。

ハードリンクとシンボリックリンクはそれぞれ異なる使用シナリオを持ちます。どちらのリンクタイプを選ぶかは特定のニーズとファイルシステムの制約に依存します。