高度な検索
Developer Connection
Member Login ログイン | ご入会 ADC連絡先

Technical Q&A QA1351
Directories Appear as Volume Aliases

Q: Mac OS X 用のネットワークファイルシステム(VFS プラグイン KEXT)を作成しています。BSD レイヤではすべてがうまく機能しているように見えるのですが、Finder は非常に混乱していて、ファイルシステム上のすべてのディレクトリがボリュームエイリアスとして表示されてしまいます。これを修正するには、どうすればよいのですか。

A: この問題を修正するには、ボリューム上のすべてのオブジェクトが stat によって返される st_dev フィールドに同じ値を返すようにする必要があります。さらに、この値はボリューム自体のデバイス番号と一致しなければなりません。システムは statfs を呼び出し、statfs 構造体の f_fsid 配列の最初のワードからデバイス番号を取り出すことで、デバイス番号を取得します。この番号が stat の返す値と一致するようにしなければなりません。

注意: システムが statfs の返す f_mntfromname フィールドからデバイス情報を取得すると考える方がいるかもしれません。しかし、ボリュームがネットワークボリュームの場合、このフィールドにはデバイスノードパスが含まれていません。

この値の一般的なデータフローは以下のとおりです。

  • ローカルファイルシステムの場合、マウントエントリポイント (examplefs_mount) はデバイスノードへのパスを含む引数が指定されて呼び出されます。ファイルシステムは(namei を使用して)このパスを参照し、デバイスの vnode(これを devvp と呼ぶことにします)を見つけ出す必要があります。次に、ボリュームの f_fsid を次のように初期化します。

    mp->mnt_stat.f_fsid.val[0] = (long) devvp->v_rdev;

    mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;

  • ネットワークファイルシステムの場合、マウントエントリポイント (examplefs_mount) は vfs_getnewfsid を呼び出して、ボリュームの f_fsid を初期化する必要があります。これにより、f_fsid には、ボリュームを一意に識別する合成値が設定されます。

  • statfs エントリポイント(examplefs_statfs)では、statfs 構造体の f_fsid フィールドに必ず適切な結果を返してください。システムはこの構造体の初期値をボリュームの mnt_stat 構造体から取得するため、ほとんどの場合、何もする必要はありません。

  • getattr エントリポイント(examplefs_getattr)で、デバイス番号(mp->mnt_stat.f_fsid.val[0])を vap->va_fsid に返すと、カーネルがその値を stat 構造体の st_dev フィールドにコピーすることができ、それが呼び出し側に返されます。

  • ボリュームが ATTR_CMN_DEVID 属性(詳細については、テクニカル Q&A QA1327「Documentation for getattrlist を参照)をサポートしている場合、その値は stat によって返される st_dev 値と一致する必要があります。

  • ボリュームが ATTR_CMN_FSID 属性をサポートしている場合、その値は statfs によって返される f_fsid 値に一致する必要があります。

このドキュメントの残りの部分では、デバイス番号を取り違えると、観察された症状がいかにして引き起こされるかについて説明します。この問題を修正して、次のバグに取りかかりたいだけなら、説明を読み飛ばしてもかまいません。逆に、Mac OS X の Carbon File Manager と BSD レイヤとのやり取りについて知りたい場合は、ぜひこのまま読み続けてください。

どうなっているのかを理解するには、BSD と Carbon がファイルシステム全体を表す方法の違いを理解する必要があります。BSD のもとでは、ファイルシステムは単一のツリーです。各ボリュームはツリーのディレクトリ(マウントポイント)としてマウントされ、そのディレクトリを渡り歩くことでボリューム間を移動することができます。BSD プログラムはこのことを認識しており、問題なくそれに対処できます。

これに対して、Carbon はファイルシステムをツリーのフォレストとして表します。各ボリュームにはルートディレクトリがあり、その下にディレクトリのツリーが広がっています。各ボリュームが個別の構成要素であるため、Carbon プログラムでは、ボリュームのディレクトリ構造内を移動したときに別のボリュームに移動する場合があることを想定していません。

Mac OS X は、BSD プログラムのための BSD のセマンティクスと Carbon プログラムのための Carbon のセマンティクスを提供する必要があります。BSD のセマンティクスは Mac OS X のネイティブなファイルシステムのセマンティクスなので、その部分は簡単です。Carbon のセマンティクスを提供するのは厄介です。Carbon File Manager は、ネイティブな BSD API 上で Carbon のセマンティクスをエミュレートしなければなりません。これにはいくつかの微妙な要領が必要になり、ファイルシステム実装者をつまずかせる可能性があります。そのため、これは一般的な問題の一例にすぎません。Carbon プログラムを正しく動作させるためには、VFS プラグインを慎重にコーディングする必要があります。

この事例では、マウントポイントが中心課題になります。Carbon File Manager はディレクトリ内でマウントポイントに遭遇しても、Carbon プログラムではディレクトリツリーをナビゲートするときに複数のボリュームを横断することが想定されていないため、マウントポイントをプログラムに直接渡すことができません。代わりに、Carbon File Manager は合成エイリアスと呼ばれるものを返します。Carbon プログラムにとって、この合成エイリアスはエイリアスファイルのように見えます(ファイルの Finder フラグの kIsAlias ビットが設定されています)。Carbon プログラムは、この「エイリアス」をたどりたい場合には、Alias Manager を呼び出してエイリアスを解決します。Alias Manager は合成エイリアスを認識し、対象ボリュームのルートディレクトリの参照を返すことでエイリアスを解決します。そのため、Carbon プログラムにとって、マウントポイントは対象ボリュームのルートディレクトリのエイリアスのように見えます。

重要: Carbon プログラムでは、Alias Manager(FSIsAliasFileFSResolveAliasFile、またはこれらの旧版)を使用して、エイリアスファイルを検出して解決する必要があります。エイリアスファイルを手動で解釈しないようにしてください。手動で解釈すると将来、互換性に問題が生じる可能性があります。

注意: デバッグ目的のためだけに、マウントポイント合成エイリアスファイルは Finder フラグの kIsAlias ビットが設定され、ファイルタイプが 'lcmt'、ファイルクリエータが 'rhap' となっています。

注意: Carbon File Manager はシンボリックリンクをサポートするために、非常によく似たメカニズムを使用します。

この事例では、Carbon File Manager がファイルシステム上のあらゆるディレクトリをマウントポイントとして解釈しているために、Carbon プログラム(Finder を含む)からすべてのディレクトリがボリュームのエイリアスに見えるのです。重大な問題はその理由です。Carbon File Manager は、ファイルシステムオブジェクトに関連付けられているデバイス番号(stat が返す stat 構造体の st_dev フィールド)を使用して、マウントポイントの変更を判断します。ディレクトリを調べるときに、Carbon File Manager はディレクトリの st_dev と、そのディレクトリが属するボリュームに関連付けられているデバイス番号を比較します。今回の事例のファイルシステムのように、それらが異なる場合、ディレクトリがマウントポイントを示しているものと見なされます。そして、ボリュームの合成エイリアスが返され、Finder がそれをボリュームエイリアスとして表示します。(前述のように)デバイス番号をすべて一致させると、Carbon File Manager はディレクトリをディレクトリとして認識するため、問題はなくなります。

ドキュメントの改訂履歴

日付メモ
2004-05-25最初のバージョン

掲載日: 2004-05-25