なぁFUSE+fusepyで遊ぼうじゃないか
http://fuse.sourceforge.net/:FUSEって言うのはFilesystem on USErspaceの略で、ユーザスペースで動くアプリケーションとしてファイルシステムを実装できる楽しいシステムのことです。Linux2.4x or 2.6xカーネルに対応しており、カーネルモジュール+ライブラリとして提供されてます。*1
ユーザ空間よりVFSを通してFUSEカーネルモジュールに渡ったファイル要求は、再びユーザ空間に戻され、libfuseを用いて実装したアプリケーションに操作が渡ります。FUSEを使ったときに我々が作るのは、このlibfuseを用いたアプリケーション部分だけです。
で、生のFUSEを触るのも良いのですが、このFUSE、各種言語のバインディングがやたらと充実しています。PythonやRubyはもちろん、GaucheやHaskellにもあったりするほど。
バインディングを利用した方がC99上で生FUSEを扱うよりも色々と楽になるので、今回はUbuntu8.04+FUSE+fusepy*2でファイルシステムを実装する方法について簡単に説明します。
事前準備
- Ubuntu8.04(32bit/64bit)
- apt-get install libfuse2(他にもう多少必要だったかも)
- http://code.google.com/p/fusepy/よりfusepyをゲット
ちょっと触ってみる
fusepyは一つのファイルによって成り立っており、我々はそれをライブラリとして利用しつつファイルシステムを構成することになります。fusepyを解凍するとfuse.pyとexample.pyってのが出て来て、まあどっちがなんなのかは分かると思いますが、example.pyが我々が実装するやつですね。
でまぁ、色々書いてあってちょいとひと目じゃ分かりにくいと思うので、とりあえず実行してみるべき。
$ mkdir /tmp/fuse <-マウントポイント作ってます $ python example.py /tmp/fuse
制御が帰らなくなりますが、他の端末からmountしてみると、確かに/tmp/fuseに何かがマウントされてるのが確認できます。プログラムを終了させたいときは $ umount /tmp/fuse で終了します。この辺の動作はexample.pyのクセです、多分変えられます。
ここでマウントされなかったらFUSEインストールが未完成なので、FUSE関係でインストールしていないものがないか確認してください。
で、他の端末から色々叩いてみると、確かにファイルシステムが構成されているのが分かります。
$ ls /tmp/fuse $ cat > /tmp/fuse/somefile hoge[C-d] $ ls /tmp/fuse somefile $ cat /tmp/fuse/somefile hoge $ rm /tmp/fuse/somefile $ ls /tmp/fuse $
じゃあ作りましょう
example.pyの動作は前述の通りで、なにやらファイルシステムが作られるってことは分かりました。
じゃあさっそく、fusepyを使ってファイルシステムを作ってみましょ。
fusepyの使い方は、このfuse.pyをimportして、fuse.FuseOperationsを継承したクラスでfuse.FuseOperationsのメンバ関数をオーバーライドするだけ、です。あとまぁfuse.FUSE関数を呼び出すif文を書きますが、これはイディオムとしてコピペです。私はこれ変えるとどうなるのか良く知りません。
import fuse class MyOperations(fuse.FuseOperations): pass if __name__ == "__main__": _fuse = fuse.FUSE(MyOperations(), foreground=True, fsname="ExampleFS")
これが最低限の骨子。
何を実装すれば良い?
簡単に、実装される命令について表にしました。
通常ファイル操作 | ディレクトリ操作 | リンク操作 | 説明 |
---|---|---|---|
open | opendir | - | openします |
release | releasedir | - | closeします |
read | readdir | readlink | readします |
write | - | - | writeします |
create,open | mkdir,open | symlink,link | 新規作成が行われます |
unlink | rmdir | unlink | 別名remove |
truncate,ftruncate | - | - | truncate(2) |
inode操作 | 説明 |
---|---|
getattr,stat | stat(2); ファイルのメタ情報を取得する |
chmod | chmod(2) |
chown | chown(2) |
utimens | utime(2); 最終時刻を変更する |
access | access(2); 別に実装しなくて良い |
その他 | 説明 |
---|---|
statfs | statfs(2) ファイルシステム情報 |
destroy | ファイルシステムをumountするときに呼び出される |
全てを実装しなくても動作するのがFUSEの親しみやすいところです。lsを行いたいならopendir/readdir/releasedirのみ実装すれば動作しますし、さらにls -lを行いたいならばstat(またはgetattr)も実装してしまえば十分です。とりあえず遊んでみたいなら、この表にあるように部分ごとに実装してくと分かりやすいはずです。
と、ここまで書けばこの記事読むような人は分かると思うのであとの説明は省略します。
気が向いたら明日、簡単な例とともに続きを書くかも知れません。でもニッチすぎるのであんま読む人いないだろな。