なぁFUSE+fusepyで遊ぼうじゃないか

http://fuse.sourceforge.net/:FUSEって言うのはFilesystem on USErspaceの略で、ユーザスペースで動くアプリケーションとしてファイルシステムを実装できる楽しいシステムのことです。Linux2.4x or 2.6xカーネルに対応しており、カーネルモジュール+ライブラリとして提供されてます。*1
ユーザ空間よりVFSを通してFUSEカーネルモジュールに渡ったファイル要求は、再びユーザ空間に戻され、libfuseを用いて実装したアプリケーションに操作が渡ります。FUSEを使ったときに我々が作るのは、このlibfuseを用いたアプリケーション部分だけです。
で、生のFUSEを触るのも良いのですが、このFUSE、各種言語のバインディングがやたらと充実しています。PythonRubyはもちろん、GaucheHaskellにもあったりするほど。
バインディングを利用した方がC99上で生FUSEを扱うよりも色々と楽になるので、今回はUbuntu8.04+FUSE+fusepy*2ファイルシステムを実装する方法について簡単に説明します。

これまでのまとめ

FUSEおもしれーからFUSE+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)も実装してしまえば十分です。とりあえず遊んでみたいなら、この表にあるように部分ごとに実装してくと分かりやすいはずです。


と、ここまで書けばこの記事読むような人は分かると思うのであとの説明は省略します。
気が向いたら明日、簡単な例とともに続きを書くかも知れません。でもニッチすぎるのであんま読む人いないだろな。

*1:MacFUSEとかReFUSEとかDokanとか、他のOSにも対応するものが作られています

*2:Pythonバインディング fusepy http://code.google.com/p/fusepy/ サポートしてるOSはUbuntu8.04 or Macのみ