inode とは何か:ファイル名とファイル実体の分離

Unix 系ファイルシステムでは、ファイル名とファイルの実体は別々に管理されている。この分離を実現するのが inode(アイノード)という仕組みだ。

ファイル名はただのラベル

ファイル名は inode への「参照」にすぎない。実際のファイルデータやメタデータは inode に格納されている。

ファイル名

人間が識別するためのラベル。ディレクトリ内に「ファイル名 → inode 番号」のペアとして保存される

inode

ファイルの実体を管理するデータ構造。ファイルサイズ、パーミッション、所有者、タイムスタンプ、データブロックの位置などを保持する

# inode 番号を確認する
ls -i data.txt
# 1234567 data.txt

# stat でより詳細な情報を表示
stat data.txt
# File: data.txt
# Size: 1024       Blocks: 8          IO Block: 4096   regular file
# Device: 801h/2049d  Inode: 1234567   Links: 1
# Access: (0644/-rw-r--r--)  Uid: ( 1000/   user)   Gid: ( 1000/   user)
# Access: 2024-01-15 10:30:00.000000000 +0900
# Modify: 2024-01-15 10:25:00.000000000 +0900
# Change: 2024-01-15 10:25:00.000000000 +0900

inode に格納される情報

inode にはファイル名以外のすべての情報が格納される。

ファイルタイプとパーミッション

通常ファイル、ディレクトリ、シンボリックリンクなどの種別と、rwx のアクセス権限。

所有者情報

UID(ユーザー ID)と GID(グループ ID)。

タイムスタンプ

atime(最終アクセス時刻)、mtime(最終更新時刻)、ctime(メタデータ変更時刻)の 3 種類。

データブロックへのポインタ

ファイルの実データがディスク上のどこにあるかを示すポインタ。大きなファイルは間接ポインタを使う。

注意すべきは、inode にはファイル名が含まれないことだ。ファイル名はディレクトリ側が管理している。

ハードリンクの仕組み

inode とファイル名が分離しているおかげで、1 つの inode に複数のファイル名を付けられる。これがハードリンクだ。

# ハードリンクを作成
ln original.txt hardlink.txt

# 両方とも同じ inode 番号を持つ
ls -i original.txt hardlink.txt
# 1234567 original.txt
# 1234567 hardlink.txt

# リンクカウントが 2 になる
stat original.txt | grep Links
# Links: 2
import os

# Python からも inode 番号を確認できる
stat1 = os.stat("original.txt")
stat2 = os.stat("hardlink.txt")

print(stat1.st_ino)  # 1234567
print(stat2.st_ino)  # 1234567(同じ)
print(stat1.st_ino == stat2.st_ino)  # True

ハードリンクは「同じ inode を指す別の名前」であり、コピーではない。どちらの名前でファイルを変更しても、同じ実体が変更される。

シンボリックリンクとの違い

シンボリックリンク(ソフトリンク)は inode の仕組みとは異なる。

ハードリンク

同じ inode を直接参照する。元ファイルを削除しても、リンクカウントが 1 以上なら inode は残る

シンボリックリンク

ファイルパス(文字列)を保持する別の inode。元ファイルを削除すると「壊れたリンク」になる

# シンボリックリンクは別の inode を持つ
ln -s original.txt symlink.txt

ls -i original.txt symlink.txt
# 1234567 original.txt
# 9876543 symlink.txt(別の inode)

inode 番号でファイルを識別する

ファイル名ではなく inode 番号でファイルを識別するのが Unix の流儀だ。

import os

def same_file(path1, path2):
    """2 つのパスが同じファイルを指すか判定"""
    stat1 = os.stat(path1)
    stat2 = os.stat(path2)
    # デバイス ID と inode 番号の両方が一致すれば同じファイル
    return (stat1.st_dev, stat1.st_ino) == (stat2.st_dev, stat2.st_ino)

# または os.path.samefile を使う
print(os.path.samefile("original.txt", "hardlink.txt"))  # True

デバイス ID も確認するのは、異なるファイルシステム間では inode 番号が重複する可能性があるためだ。

inode の上限

ファイルシステムには inode 数の上限がある。ディスク容量に余裕があっても、inode を使い切ると新しいファイルを作成できなくなる。

# inode の使用状況を確認
df -i
# Filesystem      Inodes  IUsed   IFree IUse% Mounted on
# /dev/sda1      6553600 234567 6319033    4% /

小さなファイルを大量に作成するシステム(メールサーバーなど)では、inode 枯渇が問題になることがある。