クイック エンジニアリングブログ

株式会社クイック Web事業企画開発本部のエンジニアリングチームが運営する技術ブログです。

シンボリックリンク内の相対パスの動き

はじめまして。
インフラを担当してますmatsBです。

とても限定的な話ですが、最近シンボリックリンクに興味を持ったので
その話をしたいと思います。

ディレクトリのシンボリックリンクを張ったら、プログラム内で相対パスを使うのは
"やってはいけない事"ってのは有名な話です。
"やってはいけない事"の理由は簡単で、シンボリックリンク内のディレクトリで
相対パスを使うとリンク元のディレクトリを参照するから。
ですね。



今回は改めて、
なんでリンク元のディレクトリを参照するか
を解説したいと思います。



言葉で説明すると長くなってしまうので、実際にやってみるのが早いですね。

ってことで、/home/user の配下にAとBのディレクトリを用意して
Bの1ディレクトリをAのシンボリックリンクにして
シンボリックリンク内で相対パスを実行して
"やってはいけない事"を実際に再現してみます。

AとBに同じファイル名で別内容のファイルを用意して、Aディレクトリにシェルを追加。

[user@localhost ~]$ cat /home/user/A/lib/test.txt
A.txt
[user@localhost ~]$ cat /home/user/B/lib/test.txt
B.txt
[user@localhost ~]$ cat /home/user/A/dir/test.sh
#! /bin/bash
/bin/cat ../lib/test.txt

BにAのシェルが置いてあるディレクトリのシンボリックリンクを張る。

[user@localhost ~]$ ln -s /home/user/A/dir /home/user/B/dir
[user@localhost ~]$ ls -l /home/user/B/
合計 0
lrwxrwxrwx 1 user user 16  85 13:15 dir -> /home/user/A/dir
drwxr-xr-x 2 user user 21  85 14:33 lib

Bの方でシェルを実行。

[user@localhost ~]$ cd /home/user/B/dir/
[user@localhost dir]$ ./test.sh
A.txt
[user@localhost dir]$

とまぁ、Bディレクトリで../を実行しているのにリンク元のAディレクトリを参照してますね。


これは、catコマンドの中でgetcwdを使っているが、getcwd はinode番号を元に
親ディレクトリをたどってファイルパス名の値を返すからみたいです。

ウィキペディアからの引用ですが。
inode - Wikipedia

オペレーティングシステムは一度ファイル名を inode番号に変換すると、ファイル名の方を忘れてしまう。従って、getcwd() や getwd() といったライブラリ関数は "." ディレクトリに対応する inode 番号からその親ディレクトリを捜し、最終的に "/" ディレクトリまでたどることでフルパス名を得ている。


ってことで、、、
じゃあ実際にinode番号を確認していくと

[user@localhost ~]$ ls -lai [AB]/dir/
A/dir/:
合計 4
1610961388 drwxr-xr-x 2 user user 20  85 17:20 .
 537080780 drwxr-xr-x 4 user user 26  85 17:20 ...
1610961394 -rwxr--r-- 1 user user 39  85 17:20 test.sh

B/dir/:
合計 4
1610961388 drwxr-xr-x 2 user user 20  85 17:20 .
 537080780 drwxr-xr-x 4 user user 26  85 17:20 ..
1610961394 -rwxr--r-- 1 user user 39  85 17:20 test.sh

A/dir/もB/dir/も".."のinode番号は「537080780」ですね。
ではinode番号「537080780」はどこのことなのか見てみると。

[user@localhost ~]$ ls -lai [AB]
A:
合計 4
 537080780 drwxr-xr-x 4 user user   26  85 17:20 .
 537080781 drwx------ 7 user user 4096  85 17:20 ..
1610961388 drwxr-xr-x 2 user user   20  85 17:20 dir
    864335 drwxr-xr-x 2 user user   21  85 14:33 lib

B:
合計 4
1075097284 drwxr-xr-x 3 user user   26  85 14:40 .
 537080781 drwx------ 7 user user 4096  85 17:20 ..
1075097285 lrwxrwxrwx 1 user user   16  85 14:40 dir -> /home/user/A/dir
1610961389 drwxr-xr-x 2 user user   21  85 14:33 lib

inode番号「537080780」はAの"."と同じでした。
って事はinode番号「537080780」とはAディレクトリの事を指しています。

つまり、B/dir/内で".."を指定するとAディレクトリを指すことになります。
まぁ当たり前といえば、当たり前の話ですね。


シンボリックリンクって使ってはいたけど、意外とどんな動きなのかを
調べたりする機会がなかったりします。
凄く限定的な情報ですが、この情報をどこかで活用する機会があれば
いいなと思っています。