case の insensitive と preserve
Mercurial で case 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 OS や Cygwin 環境の場合、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 OS と Cygwin の中間的な挙動。利用者的な利便性で言えば、これが一番妥当な気がする。
環境 | ファイル名補完 | getcwd() |
---|---|---|
Mac OS | 厳密一致 | 本来の文字大小 |
Cygwin | 大小無視 | 指定文字列 |
Windows | 大小無視 | 本来の文字大小 |
何にしても、ややこしい話だ ... orz