彷徨えるフジワラ

年がら年中さまよってます

case の insensitive と preserve

Mercurialcase insensitive filesystem 周りの修正をする際に仕込んだ知識のまとめエントリその4。

case insensitive filesystem とは言うものの、あくまで『文字大小に関わらない一致判定を行う』というだけで、文字大小に関する情報が破棄されるわけではない。

例えば Windows でも Mac OS でも、文字大小が混在する名前は文字大小の情報がそのまま保存 (preserve) される:

$ echo a > mIxEdNaMe
$ ls
mIxEdNaMe
$ python -c "import os; print os.listdir('.')"
['mIxEdNaMe']
$

指定パターンとの合致判定における性能劣化を考えると、strcasecmp() などを使用するよりは:

  • ファイル名の文字大小を正規化 (lower or upper) して媒体に格納
  • 指定されたパターンの文字大小を正規化
  • 媒体に格納されたファイル名情報と strcmp() で一致確認

という『文字大小の情報は破棄して格納』な実装の方がコストは安いのだけれども、何らかの理由から『文字大小は保存しておいた方が良くね?』という判断が働いたのかな?
『文字大小をそのまま格納』/『小文字がデフォルト』な X68000 で書き出した FDD の内容を、DOS 時代の PC98 で読み出せなくて難儀した記憶があるので、少なくとも DOS 時代の FDD に関しては『正規化後に格納』を前提としていた筈。

ということは、NT 系での路線変更ってこと? > Windows

ところで、Mac OSCygwin 環境の場合、cd コマンドによるディレクトリ移動先に関しても、一見すると文字大小の情報が保持されているように見える。

$ pwd
/User/fujiwara/tmp
$ mkdir mIxEd
$ cd MIXED
$ pwd
/User/fujiwara/tmp/MIXED
$

しかし Python 経由で確認すると、Mac OS に限っては:

$ pwd
/User/fujiwara/tmp/MIXED
$ python -c "import os; print os.getcwd()"
/User/fujiwara/tmp/mIxEd
$

というように、ディレクトリ本来の文字大小が正しく得られる。getcwd(3) を使用した C プログラムでも結果は同様。

# 多分 Python の os.getcwd() は getcwd(3) 呼び出しだと思うけど....

ここで環境変数の設定状況を見ると:

$ env | grep -i mixed
PWD=/User/fujiwara/tmp/MIXED
$

といった具合なので、シェルがそのまま PWD 環境変数に保存したディレクトリ指定の文字列を、pwd コマンドがそのまま表示、という流れではないかと推測。

その一方で、Cygwin 環境では cd に指定した文字列が getcwd() でもそのまま有効になっている。

更に bash における補完処理に関しては、Mac OS では文字大小を無視せずに厳密一致で実施される一方で、Cygwin では文字大小を無視して候補を列挙してくれる、という具合。

Windows (+ コマンドプロンプト) の場合、ファイル名補完は文字大小を無視するけれど、getcwd() 挙動では本来の文字大小を維持という、Mac OSCygwin の中間的な挙動。利用者的な利便性で言えば、これが一番妥当な気がする。

環境ファイル名補完getcwd()
Mac OS厳密一致本来の文字大小
Cygwin大小無視指定文字列
Windows大小無視本来の文字大小

何にしても、ややこしい話だ ... orz