Title

2014年3月の投稿一覧

OS X Mountain LionのSMB実装に問題を見つけた

MacOS MountainLion で濁点や半濁点のあるファイルやフォルダがあると不具合が起きるとのご報告を受けて調査した結果、MacOS側に問題を発見しました。

SMBパケットをキャプチャしてみると以下のようになりました。
ハイライトで示した部分は、ディレクトリ内のファイル一覧を取得した結果です。

「名称未設定フォルダ」というフォルダがあります。
「名称未設定フォルダ」のUnicode(NFC正規化)のコードは以下で、18バイトです。
540D 79F0 672A 8A2D 5B9A 30D5 30A9 30EB 30C0

以下はMacOSX Marvericksをサーバにして、SMB1でアクセスファイル一覧を取得した結果の一部です。
18バイトのUTF16LEの文字列で「名称未設定フォルダ」が取得できています。

140324osx_marvericks

ところが、MacOSX MountainLion同じ事を行うと、ファイル名の長さが20バイトで、
540D 79F0 672A 8A2D 5B9A 30D5 30A9 30EB 30C0 0000
という結果が返ってきます。

140324osx_mlion

試しに「名称未設定フォル」の濁点を取って「名称未設定フォル」に変更すると、
540D 79F0 672A 8A2D 5B9A 30D5 30A9 30EB 30BF
という18バイトの正しい結果が返ってきます。

140324osx_mlion2

よって、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実装はあまり例がないようなのですが、実装時にはこの部分おさえておかないと不具合出ますね。

SMBとUnicodeファイル名正規化問題

かつて、LinuxからSambaを使ってWindowsのファイル共有にアクセスすると、文字コードの変換の問題で大変苦労しました。

時代は流れ、LinuxでもWindowsでもUnicodeが標準になりました。
というわけで、一般的にSMBを使う分には文字コードで苦労することはほぼなくなりました。

しかし・・・。

とりあえず以下の画像をご覧ください。
これはWindows8のエクスプローラーの画面です。

SnapCrab_NoName_2014-3-23_1-27-56_No-00

何かおかしいところにお気づきでしょうか。
おかしいですよね。
いいおっさんがプリキュア・・・じゃなくて、同一のファイル名が同じフォルダに存在しています。

実はこれ、「ピ」と「プ」の文字がUNICODEの結合文字列になっています。

通常、Windowsで「プリキュア」と入力した場合、「プ」の文字はU+30D7になります。
しかしMacOSで「プリキュア」と(ファイル名として)入力した場合、「プ」の文字はU+30D5 U+309Aになります。

U+30D5は「フ」です。
U+309Aは半濁点記号です。
つまり、「フ」+「゜」の合成で表現されます。
(なお、ここに書いた「゜」はU+309Cで、合成用ではなくそういう1文字ですので念のため)

Unicodeではこのような複数の表現方法があります。
混ざってる何かと困るので、普通は同一コードになるように正規化して扱います。
合成した方を使うのをNFC(Normalization Form Canonical Composition)、分解した方を使うのをNFD(Normalization Form Canonical Decomposition)と言います。

さて、最初の画像のファイル名ですが、「パ」と「プ」の表現方法を結合文字列、合成文字、混ぜてあります。
結果として4パターンの同名ファイル名が出来てしまったわけです。

何故かWindowsは上記のような状態を許してくれます。
許しているというか、初期の頃になんの正規化もせず扱ってしまったため、以後もそのままになっているんだと思います。(憶測)

さて、一方MacOSですが、上記のようなNFD,NFCの混在を許してくれません。
必ずNFDライクな正規化をされます。(正確にNFDでないのがまた困るんですが・・・)
iOSも一緒です。
よってファイル共有をすると大変困ります。
SMBには明確な仕様がない(もしかしたらあるかもしれなけど、ドキュメント読む限り発見できず)。
おそらくWindowsなのでNFCのUTF16 Little endianなんでしょうが、NFDでもプロトコルとしては問題なく(というかノータッチで)動きます。

さて、どう実装するのが正解なのでしょうか。
困りました。

VisualStudio2013でビルドするとWindowsXP/2003Serverで起動できない

VisualStudio2013では、デフォルトの設定でWindowsXPが切り捨てられています。

フレームワークのバージョンとかでなく、素のWindowsAPIのみを利用していても起動できません。
さすがにもうWindowsXPはサポートしなくても良いのかもしれませんが、Windows2003ServerはWindowsXPと同じ扱いですので、WindowsXPで起動できないとWindows2003Serverでも起動できません。
(Windows 2003Serverは15年7月くらいまでサポート期間があります・・・)

以下の設定を変更すると起動できるようになります。

140321vs2013

もはや動作確認環境もなく、なかなか気づきにくいので気をつけないといけませんね。

・・・しかしVisualStudio高いよねーー。。
自分の作るWindowsアプリケーションは本当に素のC++で書いているので別にどんなコンパイラでもコンパイルできるんですよね。だから高く感じますが・・・
しかし、VisualStudio2013のエディタはかなり良くなりました。エディタとして買ってます。

カレンダー

2014年3月
 12
3456789
10111213141516
17181920212223
24252627282930
31  

▲Pagetop