OS X Mountain LionのSMB実装に問題を見つけた
Posted on 2014年3月24日(月) 22:11
MacOS MountainLion で濁点や半濁点のあるファイルやフォルダがあると不具合が起きるとのご報告を受けて調査した結果、MacOS側に問題を発見しました。
SMBパケットをキャプチャしてみると以下のようになりました。
ハイライトで示した部分は、ディレクトリ内のファイル一覧を取得した結果です。
「名称未設定フォルダ」というフォルダがあります。
「名称未設定フォルダ」のUnicode(NFC正規化)のコードは以下で、18バイトです。
540D 79F0 672A 8A2D 5B9A 30D5 30A9 30EB 30C0
以下はMacOSX Marvericksをサーバにして、SMB1でアクセスファイル一覧を取得した結果の一部です。
18バイトのUTF16LEの文字列で「名称未設定フォルダ」が取得できています。
ところが、MacOSX MountainLion同じ事を行うと、ファイル名の長さが20バイトで、
540D 79F0 672A 8A2D 5B9A 30D5 30A9 30EB 30C0 0000
という結果が返ってきます。
試しに「名称未設定フォルダ」の濁点を取って「名称未設定フォルタ」に変更すると、
540D 79F0 672A 8A2D 5B9A 30D5 30A9 30EB 30BF
という18バイトの正しい結果が返ってきます。
よって、MacOS10.8では、SMBクライアントに対してファイル名をNFCに正規化するが、正規化後のファイル名のサイズ計算に問題があると思われます。
(MacOSではNFDでのみファイルが保存されるので、NFCへの正規化がSMBの一部として行われるようです)
0000は通常文字列終端を表すので、Windowsなどではそこまでを文字列と判断して問題が起きないものだと思われます。
また、この問題はMarvericksでは発生しないので、MacOSとしては修正済みと思われます。
ComicGlassでは素直に、サーバから返してきたファイル名文字列長の後に、検索パターンである\\*を追加してフォルダの階層を辿っています。
その結果、文字列の途中に0000が入ってしまい、追加した\\*が無効になってしまいます。
影響としては、ファイル一覧を取得できない他、ファイルのオープンもできなくなります。
対策として、受け取ったファイル名に0000(‘\0’)が含まれていたらファイル名長を計算しなおす修正を入れます。
しかし、(おそらく)正しく実装していても相手によって不具合が起きる、、SMB互換性の確保は難しいです。
特にMacOSとiOS以外では普通ファイル名にNFCを使いますしが、NFDでもファイル名をつけられます。
MacOSとiOSでは、必ずシステムによってNFD(の変形版・・)の正規化がされますので問題が顕在化します。
Objective-CのSMB実装はあまり例がないようなのですが、実装時にはこの部分おさえておかないと不具合出ますね。