まずはどのようなnodeが存在するかを確認してみよう。リスト1(list_nodes.c、6ページ目にも掲載)はDirectoryService のAPIを使ってnodeの一覧を取得するものだ(図2)。

図2: list_node.c

図2: list_node.c

DirectoryServiceを利用するには、まずはDirectoryService/DirectoryService.hをincludeする。Mac OS Xのフレームワークは、このような形でフレームワーク名と同名の代表となるヘッダファイルが用意されており、1つのヘッダファイルをincludeするだけで必要なヘッダファイルをまとめて読み込めるようになっている。

少し話は前後するが、ビルドを行う場合は実行例12のように、「-framework」を指定した上でgccを起動する。「-framework」はApple独自の拡張で、これを指定することで、frameworkフォルダ配下のHeadersフォルダが自動的にヘッダファイルの検索範囲に入り、その下のヘッダファイルを「フレームワーク名/ヘッダファイル名」の形で参照できるようになる。また、frameworkフォルダ直下のフレームワークと同名の共有ライブラリがリンクされる。「-I」「-L」「-l」の3つを兼ね備えたオプションなのだ。

実行例12: ビルドを行う際は「-framework」を指定した上でgccを起動する

% cc -o list_nodes list_nodes.c -framework DirectoryService
% ./list_nodes
Node No. 01, /BSD/local
Node No. 02, /Local/Default

25行目のdsOpenDireService関数でDirectoryServiceのサーバと接続を行う(図2)。DirectoryServiceはMac OS X起動時に起動される、Open Directoryの中心となるサーバであり、DirectoryService APIを利用するクライアントは全てこのDirectoryServiceサーバに接続し、実際のディレクトリサービスへのアクセスはこのDirectoryServiceがプラグインを通して行う。なお、この通信にはMach IPCが用いられている。

29行目のdsGetDirNodeCountで、DirectoryServiceで現在有効なnodeの数を確保し、52行目のdsGetDirNodeListでその一覧を確保する。

29行目から52行目までは何をしているかというと、このdsGetDirNodeListのためのバッファを用意している。

DirectoryService APIではしばしばこのような生のバッファを確保し、APIに渡すという行為が行われる。このバッファの内部は直接アクセスしがたいデータであり、65行目からにあるようにDirctoryServiceの定義する関数を使って読み取っていく形となる(図2)。なお、バッファサイズが足りず、全てのデータを読み込めない場合はdsGetDirNodeListの最後の引数のlistContextのようなコンテクストを確保する変数に状態が保存され、これを引数に再度呼び出すことで続きから読み込める。listContextの値がNULLの場合はもう続きのデータがないという意味のため、これを条件として「do - while」文でループを作成している。

dsclなどOpen Directory関連のツールでは、nodeやrecordを指し示すパスは「/」区切りで表現されるが、DirectoryServiceの内部では、パスは要素を並べたリストの形で表現されている。65行目のdsGetDirNodeName関数では、バッファからパスを1つ読み出しているが、これはそうしたリストであるため、続く68行目でこれを第3引数の文字を区切り文字として連結した文字列に直している。

なお、こうしたAPIは戻り値について動的にメモリを確保して返すため、適宜開放を行わないとメモリリークが発生する。

バッファの確保をさせたと思えばAPIによってはメモリを自動確保するため、慣れるまではこのメモリリークとの戦いが続くことだろう。なぜCore Foundationの提供する参照カウントで管理されたオブジェクトを利用しないのか、理解に苦しむ。