中学英語811710 views
小学算数1200427 views
Computer368106 views
いろは3010814 views
MathPython497343 views
りんご209490 views
小学理科719870 views
教育149510 views
LaTeX962153 views
高校国語788336 views
Help
Tools
NewsSpreadsheetCalendarSlidesTier ListPen ToolIllustrationCrayonPixel ArtASCII ArtPerspectiveEndless StairsGraphMind MapER DiagramFamily TreeMemeCurved TextImage EditorMosaicRetro FilterPencil SketchOCR/HighlighterMakeup EditorFaviconVideo TrimmerScrolling VideoVideo TitleColor PickerColor ExtractorBonfireFireworksWater RippleWater SplashBreaking GlassWood GrainMarble TextureCSS ButtonIcon MakerBar ChartGrouped Bar ChartStacked Bar ChartPie ChartLine ChartArea ChartStacked Area ChartScatter Plot3D Bar Chart3D Pie ChartBar Chart RaceBubble ChartPopulation PyramidPictogramEarningsCandlestick ChartInvestment RiskMortgage SimulatorCalculatorMatrix CalculatorFunction GraphPolynomial ExpansionVenn DiagramField VisualizerRubik's Cube Group TheoryTraveling SalesmanVoronoi and DelaunayFractalColumn ArithmeticDraw Math FiguresArithmetic AnimationArithmetic Word ProblemsCounting with Tree DiagramsCube NetsCross SectionsMotion PathMechanicsWavesLight and LensesThermodynamicsHow Semiconductors WorkMolecular StructuresAtomic OrbitalsElectrochemical CellsChemical EquilibriumCrystal LatticesBuffer pHComplex IonsDNA Double HelixCell DivisionMembrane ChannelsNerve ImpulseRock ClassificationWeatherConstellationsSolar and Lunar Eclipses3D ModelingFloor PlanSeismic StructuresIntersection TurnMaglevCooking AnimationOrigamiLive Viewer CountGeoJSON MapRailway MapPopulation MapCrime MapLand Price MapSchool MapShrine and Castle MapHouse of Representatives MapWord MapSolitaireReversiHakoiri MusumeChessHamburgerRippleSlide Puzzle MakerNeon PinballNovel MakerJapanese Typing PracticePiano Score EditorMusic Theory

English

ディレクトリの正体:特殊なファイルとしての構造

Unix ではディレクトリも「ファイル」の一種として扱われる。ただし通常のファイルとは異なり、特殊な構造を持っている。

ディレクトリは特殊なファイル

ディレクトリの実体は「ファイル名と inode 番号のペアを格納したテーブル」だ。

通常のファイル

任意のバイト列を格納する。テキスト、画像、バイナリなど何でも入る

ディレクトリ

「ファイル名 → inode 番号」のマッピングを格納する。中身はカーネルが管理する特殊なフォーマット

# ディレクトリも inode を持つ
ls -lid /home/user
# 1048577 drwxr-xr-x 5 user user 4096 Jan 15 10:00 /home/user

# 'd' はディレクトリを示す
stat /home/user | grep "File:"
# File: /home/user
# Size: 4096       Blocks: 8          IO Block: 4096   directory

ディレクトリエントリの構造

ディレクトリ内の各エントリは「dirent(directory entry)」と呼ばれる構造を持つ。

inode 番号

エントリが指すファイルの inode 番号。

ファイル名

可変長の文字列。ファイルシステムによって最大長が異なる(ext4 では 255 バイト)。

ファイルタイプ

通常ファイル、ディレクトリ、シンボリックリンクなどを示すフラグ(一部のファイルシステムのみ)。

Python から見ると、os.scandir() がこのディレクトリエントリに直接アクセスする。

import os

# scandir はディレクトリエントリを直接読む
with os.scandir("/home/user") as entries:
    for entry in entries:
        print(f"{entry.name}: inode={entry.inode()}, is_dir={entry.is_dir()}")

os.listdir() よりも os.scandir() のほうが効率的なのは、ディレクトリエントリから直接情報を取得でき、追加の stat() 呼び出しが不要な場合があるためだ。

「.」と「…」エントリ

すべてのディレクトリには 2 つの特殊エントリが存在する。

. (ドット)

自分自身を指す。現在のディレクトリの inode への参照

.. (ドットドット)

親ディレクトリを指す。一つ上の階層の inode への参照

# . と .. の inode を確認
ls -lia /home/user
# 1048577 drwxr-xr-x 5 user user 4096 Jan 15 10:00 .
# 1048576 drwxr-xr-x 3 root root 4096 Jan 10 09:00 ..

# . は /home/user の inode
# .. は /home の inode

これが「ディレクトリのリンクカウントが 2 以上になる」理由だ。空のディレクトリでもリンクカウントは 2(自身へのエントリ「.」と親からのエントリ)。サブディレクトリを作ると、子の「…」から参照されるためカウントが増える。

なぜディレクトリを直接読めないのか

ディレクトリは特殊なファイルなので、通常の read() では中身を読めない。

# これはエラーになる
try:
    with open("/home/user", "r") as f:
        content = f.read()
except IsADirectoryError as e:
    print(e)  # [Errno 21] Is a directory: '/home/user'

カーネルがディレクトリの読み取りを禁止しているのは、フォーマットがファイルシステムごとに異なるためだ。代わりに readdir() システムコール(Python では os.scandir()os.listdir())を使う。

// C 言語では opendir/readdir を使う
#include <dirent.h>

DIR *dir = opendir("/home/user");
struct dirent *entry;
while ((entry = readdir(dir)) != NULL) {
    printf("%s: inode=%lu\n", entry->d_name, entry->d_ino);
}
closedir(dir);

ディレクトリのハードリンクは作れない

ファイルにはハードリンクを作れるが、ディレクトリには(通常)作れない。

# ディレクトリへのハードリンクは禁止
ln /home/user /tmp/userlink
# ln: /home/user: hard link not allowed for directory

ディレクトリのハードリンクを許可すると、ファイルシステムが循環参照を持つ可能性があり、多くのツール(find、du など)が無限ループに陥る危険がある。「.」と「…」は例外的に許可された特殊なハードリンクだ。

ディレクトリのサイズ

ディレクトリのサイズは「中身のファイルの合計サイズ」ではなく、「ディレクトリエントリを格納する領域のサイズ」だ。

# 空のディレクトリでも 4096 バイト(1 ブロック)
mkdir empty_dir
ls -ld empty_dir
# drwxr-xr-x 2 user user 4096 Jan 15 10:00 empty_dir

# ファイルを大量に作るとディレクトリ自体のサイズが増える
cd empty_dir
touch file{1..10000}
ls -ld .
# drwxr-xr-x 2 user user 155648 Jan 15 10:01 .

ディレクトリを「中身をリストアップするための帳簿」と考えると理解しやすい。帳簿自体のページ数と、帳簿に記録された商品の合計価格は別物だ。