managed オプションを利用したマウント
Cygwin 1.5.0 から mount 機能に導入された「managed」オプションを利用すると、大文字小文字が異なるだけのファイル名(例: Makefile と makefile)を区別することが出来るようになります。ここでは、managed オプションの利用方法と、その制限について説明します。
managed オプションとは
そもそも、Windows のファイルシステムには次のような制限があります。
- 「
\」、「/」、「:」、「*」、「?」、「"」「<」、「>」、「|」の各文字は、ファイル名として利用出来ない。 - 予約済みファイル名(デバイスファイル名)はファイル名として利用出来ない。詳細については 「予約されているファイル名(デバイスファイル名)と同名のファイルを削除する」を参照して下さい。
- ファイル名は大文字小文字を区別しない。即ち、「Makefile」と「makefile」のように、大文字小文字の違いしかないファイルは同じディレクトリ内に存在出来ない(*1)。
Cygwin も Windows アプリケーションの一種なので、Windows のファイルシステム内に格納可能なファイル名しか扱うことが出来ません。 しかし Cygwin 1.5.0 から mount に追加された「managed」オプションを利用すれば、ファイル名を Cygwin そのものに管理させることが可能になります。Cygwin がファイル名の管理を行うことによって、Windows の中の世界では許されないようなファイル名のファイルを作成することが出来るようになるわけです。尤も、Cygwin は Windows アプリケーションの一つに過ぎませんから、managed オプションが提供する世界の実現のためにかなりの無理をしています。
managed オプションが採用した手法は、次のようなものです。
- 問題のある部分は独自形式にエンコードしてしまい、Windows 上ではエンコード後のファイル名を利用する。
- Cygwin 上でファイル名を扱う場合は、ファイル名をデコードしてから利用する
具体的には、次のようにしています。
- 「
*」や「:」など、Windows ではファイル名として使えない文字を「% + ASCII」という形式で表現する。 - 大文字小文字が異なるだけのファイル名に対応するため、アルファベットの大文字は全て「% + ASCII」という形式で表現する。
- 「aux」や「prn」のような予約済みファイル名については、ファイル名の先頭を「% + ASCII」という形式で表現する。
*1: NTFS では区別することが可能ですが、互換性維持のため、区別しないようになっています。
利用方法
managed オプションを利用するには、
$ mount -u -o managed c:/somewhere /somewhere
のように「-o managed」を付けてマウントを実行します(「-o」オプションは 1.5.0 で新しく追加されたもので、複数のオプションを纏めて指定する際に利用します)。マウントの結果は次のようになりますが、マウント「somewhere」の「managed」という表示に注目して下さい。
$ ./mount.exe D:Cygwin\usr\X11R6\lib\X11\fonts on /usr/X11R6/lib/X11/fonts type system (binmode) c:\somewhere on /somewhere type user (binmode,managed) D:Cygwin\bin on /usr/bin type system (binmode) D:Cygwin\lib on /usr/lib type system (binmode) :
managed オプションの実際
大文字小文字の区別
managed オプションを有効にしてマウントしたディレクトリで、さっそく実験してみました。
$ touch makefile $ touch Makefile $ ls -la 合計 0 drwxr-xr-x+ 2 riue none 0 Jul 6ニ・17:26 ./ drwxr-xr-x+ 10 root none 4096 Jun 14ニ・21:50 ../ -rw-r--r-- 1 riue none 0 Jul 6ニ・17:26 Makefile -rw-r--r-- 1 riue none 0 Jul 6ニ・17:26 makefile
見ての通り、「Makefile」と「makefile」が同居出来ています。しかしこのディレクトリをエクスプローラなどから参照すると、「Makefile」については「%4Dakefile」というファイル名になっているということが分かります。「ABC」というファイル名であれば、Windows 上での(正しい)ファイル名は「%41%42%43」となることになります。
特殊文字が含まれるファイル
特殊文字については、Windows 環境では利用出来ない「:」、「*」、「?」の 3 文字が新しく使えるようになりました。これによって、「aaa:bbb」といったファイルを作成することが出来るようになります。特殊文字も「% + ASCII」という形式で表現されますから、「aaa:bbb」の実際のファイル名は「aaa%3Abbb」となることになります。但し、「\」、「/」、「"」「<」、「>」、「|」については、やはり利用出来ません。
$ touch 1\\A 1\/A 1\:A 1\*A 1\?A 1\"A 1\<A 1\>A 1\|A touch: creating `1\\A': No such file or directory touch: creating `1/A': No such file or directory touch: creating `1"A': No such file or directory touch: creating `1<A': No such file or directory touch: creating `1>A': No such file or directory touch: creating `1|A': No such file or directory $ ls 1*A 1:A 1?A
予約済みファイル名
予約済みファイル名は全て利用可能となっています。aux については「%61ux」、prn については「%70rn」のように、各予約済みファイル名の先頭の文字を「% + ASCII」という形式にエンコードしています。
$ touch con aux prn nul com1 lpt1 $ ls aux com1 con lpt1 nul prn
問題点
ちょっと使っただけでも、ボロボロと問題が見えてしまいました。
- 「
touch 'c:bb'」を実行したところ、C ドライブのルートディレクトリにファイル「bb」が作成されました。Cygwin は現在利用可能なドライブを全て「ドライブ文字:」という名前でマウントするため、「c:bb」は「c: ドライブ直下の bb」と解釈されてしまうのです。 - Windows 上で「大文字が含まれたファイル」を作成した場合、そのファイルを Cygwin から扱おうとすると ENOENT が返ります(ユーザから見れば、「No such file or directory」です)。少なくとも現在の Cygwin DLL は「managed モードでマウントされている場所では、ファイル名中の大文字は常に『% + ASCII』として表現される」ことを前提としているようであり、Windows 側でファイル名に直接大文字が利用されることは想定していないようです。大文字が入ると駄目なので、一部の日本語の文字(例: 「新規」)なども使えません。
- 上記に関連しますが、ASCII の大文字が含まれる日本語の文字については、「% + ASCII」のエンコーディングによって酷い文字化けを起こします。仮に「
touch '新規.txt'」を実行しようものなら、そのファイルは Windows 上では「・56・4B.txt」のように見えてしまいます。しかも、Cygwin 側でも「新規.txt」にはデコードされません。
実用に値するか?
少し使ってみただけでもこれだけの問題がある以上、全てのマウントに対して managed オプションを採用するのは危険過ぎます。必要がある場合にだけ利用するというのが正しい利用方法ではないでしょうか。特に、一般の Windows アプリケーションでファイルを頻繁に作成するようなディレクトリを managed してしまうと、悲惨な事態を招くことになると思います。