2008-12-28

Samba と rsync と Mac OS X

Mac OS X でネットワーク上のストレージを使うときに、Samba や rsync/rcp/scp などを混ぜて使うと困ることがある。

最近は MacBook Pro の内蔵ハードディスクが手狭になってきたので、当座の必要性の薄いファイルはなるべく外付けのディスクかネットワークジ上のファイルサーバにコピーをとることにしている。

必要性の高いファイルはなるべくローカルに置いておきたいし、ディレクトリツリーの構造はなるべくそのままでコピーをとりたいので rsync(1) を使ってアップデートコピーをしていた。最近の Mac OS X の rsync は、HFS(+) にちゃんと対応していて、リソースなどもよきに計らってコピーをしてくれて(-Eオプションを使う)、コピー先が別マシンのときは相手も Mac OS X でないと無視されるなど)非常に便利になっている。ただ、ここで若干の問題が生じることがあるのに最近気付いた。

Mac OS X の HFS(+) 上でのファイル名のエンコーディングと、Samba 上のファイル名のエンコーディングとは異なることが多い。Mac OS X 以外の OS を使ったマシン上のファイルシステムを Samba を使って Mac OS X から使っている人はだいたい知ってると思うけど、最近の Samba を使う限りはこれが問題になるいことは少ない。これは、アジアのペンギン: MacOS X とのファイル共有 に書かれているように、実際のファイル名のエンコーディングが異なっていても、ネットワーク上でやりとりされるファイル名のエンコーディングは問題ないように(ほぼ)統一されているからだそうだ。

SMB/CIFS でのファイル名のやりとりは、Linux や Windows では、非正規化 Precomposed UTF-16LE でやりとりされ、MacOS X では 正規化 Precomposed UTF-16LE でやりとりされています。

正規化処理を行っているか否かという違いはありますが、Linux、Windows、MacOS X のいずれも Precomposed UTF-16LE でファイル名のやりとりを行っていますので日本語ファイル名もほぼ問題なくファイル共有が出来ます。
ただし、ここに rsync や rcp など smb を介さないやりとりがあると問題が起こることがある。

つまりはこういうこと。rsync や rcp や scp などは、ファイル名に関してはなんの変換も行なわない。したがって、Mac OS X で UTF-8-MAC (前記リンク先では Unicode Normalization Form D (NFD) あるいは 正規化 Decomposed UTF-8 と書かれてますね)で表現されたファイル名のままコピー先にファイルが作成されてしまう。このコピーされたファイルを Mac OS X マシンから rsync や rcp を使ってアクセスする限りにおいては問題は生じない。

ところが、このファイルを samba を使ってアクセスすると、ときどき問題が起こる。

Linxu 上の Samba は、ローカルなファイル名が(やはり前記リンク先の表現を借りるなら)非正規化 Preomposed UTF-8 であることを前提にネットワーク向けには(smb経由では) Precomposed UTF-16LE に変換して、Mac OS X 上の samba クライアントと通信する。 ところが、rsync や rcp や scp でコピーされたファイルの名前はもともとの Mac OS X の HFS(+) 上にあったときと同じ UTF-8-MAC なので、これらのエンコーディング間で違いがある場合には Precomposed UTF-16LE へ正しく変換が行われない。UTF-8-MAC と Precompoesed UTF-8 の違いは主に濁点や半濁点などに見られるため(このへん理解があいまなのですが……)、これらが含まれる場合に困ったことになる。

たとえば、rsync でコピーしたファイルが、Samb を使ってファインダーから「見える」のに、実際にアクセスしてみると「存在『しない』」とされてしったり、場合によってはその存在さえ「見えなく」なってしまう。

一つ、実例を挙げてみる。今、Mac OS X 上で「ボ」というファイルを作ったとすると、Finder から見えるそのファイルは、「e3 83 9b e3 82 99」となっている(Mac OS X のhexdumpで確認。エンディアンの問題があるけど、ややこしいので以後 Linux 側でもこちらの表記に合わせることにする)。これを Finder で Linux (Ubuntu 8.04.1) 上の samba のボリュームにコピーすると、コピー先では「e3 83 9c」となっていて、Mac OS X で「ホ」+「゛」に decompose されていたものが、samba によって適切に変換されていることが分かる。もちろん、このファイルは Finder からは(samba を経由するので) decomposed されたように見えているのでファイル操作にはなんの問題も生じないし、Linux からも precomposed UTF-8 のファイル名として普通に扱える。

一方、samba を介さずに rsync を使って直接コピーを行なったとすると、Linux のファイルシステム上でもファイル名は変換されずに decompose された「e3 83 9b e3 82 99」となる。そして、このファイルのあるディレクトリを samba 経由でマウントすると、Mac OS X 側からこのファイルの名前は同じく「e3 83 9b e3 82 99」であるように見える。ところが このファイルにアクセスしようとすると、(sambaは)Linux 上にあるファイル名が前述のように「e3 83 9c」であることを期待するのに、そんなファイルは実際には存在しないという問題が起こる。この問題の現われ方はどうにも素直でなくて、実はこのファイルはファインダで「見る」ことはできるが、どうにも正しい(期待される)ファイルのようには見えなくなったりする(下図: 手前がローカルなボリュームに最初に作ったファイル。奥が samba でマウントしたボリューム上のファイル)。標準テキスト(本当は空のファイルなんだけど)のはずのものがコピーになるとエイリアスのように見えているし、メタデータはめちゃくちゃだし、しかも、このファイルはクリックしたとたんに Finder から見えなくなってしまう。


decomposed UTF-8 と precomposed UTF-8 でファイル名に違いがない場合にはこの問題は起こらない。だから、デジカメの写真を撮ったままのファイル名でバックアップするときには問題になることはないし、普段からファイル名に日本語を使わないような場合にも問題になることは少ない。

また、samba のサーバー側の文字設定(unix charset)を UTF-8-MAC に設定することがきれば(標準でこれができる Liinux は少なそうだ)、Mac OS X からそのボリュームを使う場合に限ってはこの問題は解決する。しかし、その場合でも Windows から アクセスしたり、Linux 上で直接ファイル操作を行う場合に問題が起こりそうなのは同じことだ。

結論としては 、samba でのやりとりとその他の方法でのファイルのやりとりは、(それぞれのファイルシステム上のファイル名のエンコーディングが異なる)クロスプラットフォームでは

混ぜるな危険

ということか。どちらからも全く問題のない解法は今のところはないし、rsync や rcp、scp などのようなプログラムの全てにファイル名の変換機能を付けるというのも非現実的(というか自分でやりたくない/ 自分ではできない )だし。

2 comments:

Anonymous said...

せっかく面白そうな表題なのですが,文章が非常にわかりずらいと思いました。

rok said...

うー、あー、分かりにくいですか。

超訳すると、

ファイル名のエンコーディングを変更しない rsync/scp/rcp などと、ファイル名のエンコーディングを変更しうる Samba とを併用すると、場合によっては見かけのファイル名は変わらないけど、実は異なるファイル名のファイルができちゃうことがあるので注意しましょう、というお話です。

図を描こうとは思ったんですが、分かりやすい図というのも文章同様になかなか難しく、途中で果ててしまったのでした。

別のエントリ(6 x 3: ハードディスクが壊れたので NAS を導入してみた)でも書いてますが、問題を避けつつ、rsync を使いたいなら、samba のボリュームをマウントして(自動かしたいなら mount -t cifs ... などして)、それに対して rsync などを使うのがいいです。Samba 2.x だと OS X でマウントできなかったりしましたが、新しめの Samba だとけっこう大丈夫みたいです。

分かりやすく書くのは難しいですねぇ …… sigh。