LoginSignup
0
0

More than 3 years have passed since last update.

Rust-FUSEで遊んでみる (ver.2019)

Last updated at Posted at 2019-08-14

概要

RustでFUSE」な記事は既出ですがバージョンが古くてそのままだとどうにもならないので、遊ぶついでに自分の記事を書こうと思いました。
FUSEが何なのかは上記の記事など私より賢い人たちの説明がたくさんあるのでそちらを参照してください。

今回やること

  • Rust-FUSEの環境を用意する
  • examples/hello.rs を試してみる
  • ちょっと改造してみる

実施した環境

  • Windows10 (Pro 64bit)
  • Hyper-V
    • Ubuntu : 19.04
    • Rust : 1.36.0 (stable)

WSLではFUSEは使えないらしいです。(2019/8段階で一般公開されていないWSL2ならどうかわかりませんが)

内容

Rust-FUSEを持ってくる

repositoryは下記です。
https://github.com/zargony/rust-fuse
READMEに書いてありますが、fuse、libfuse-dev、pkg-configをapt-getとかしておく必要があります。
Rust-FUSEのcrateを使うだけならrepositoryのソースコードは不要かもしれませんが、repositoryにあるexamples/hello.rsをビルドするためには未公開の最新版が必要です(repositoryはバージョン0.4とかになりましたがcrate.ioの方は0.3.1で放置されている……)。
なのでrepositoryをcloneしたらまずcargo buildしてみるのがいいかもしれません。

examples/hello.rsを試す

repositoryにあるexampleなhello.rsをbuildするにはCargo.tomlに下記を追記します。

Cargo.toml
  log = "0.4.6"
  thread-scoped = "1.0.2"

- #[dev-dependencies]
+ #[dev-dependencies]
  env_logger = "0.6.0"

+ [[bin]]
+ name = "hello_fs"
+ path = "examples/hello.rs"

dev-dependenciesはなんかうまいやり方があるのかもしれませんがめんどうなので上記のようになりました。
これでcargo build --bin hello_fsとかすればtarget/debug/hello_fsとかが生成されます。
下記の要領でまずマウント動作を確認できます。

> cd target/debug
> mkdir /tmp/hello_dir
> ./hello_fs /tmp/hello_dir

3つ目のコマンドをたたくとプロンプトが返ってこなくなりますがそういうものっぽいです。ソースコードにそんな感じで書いてあります。なので別のコンソールを開いたりして下記を試します。(別のコンソール開けない人はゴメンナサイ。ctrl+cで止めるとマウントしたディレクトリは死にます。)

> ls -ln /tmp
...
drwxr-xr-x 2  501   20    0  1月  1  1970 hello_dir
...
> cat /tmp/hello_dir/hello.txt
Hello World!
> sudo umount /tmp/hello_dir

アンマウントするときは普通にumountなんですよね。面白いです。

ちょっと遊んでみる

上に示したようにuid/gidが変な数字で固定されているので、マウントした人のuid/gidを答えるようにしてみます。

基本方針

ディレクトリの属性を参照したときの値はHELLO_DIR_ATTR定数から取られています。
今、このHELLO_DIR_ATTRにあるuidとgidを別の値にします。
しかし可変の値はグローバル定数にはできない&Rustはグローバル変数に厳しいので、HelloFSでちゃんと値を持つようにして初期化しつつ……という手順を取ります。
説明すると長くなるので下記のソースコードを見てもらいつつ、かいつまんで説明していきます。
https://github.com/hakua-doublemoon/rust-fuse

uid/gidの取得

ググるとnixというcrateが出てきたのでこれを使ってみます。
https://docs.rs/nix/0.15.0/nix/
Cargo.tomlに下記を追記します。

Cargo.toml
nix = "0.15.0"

これを使って下記のようにuid/gidを取得します。

examples/hello_attr.rs
use nix::unistd;
// (中略) 
pub fn dir_attr_get() -> FileAttr
{
    FileAttr {
// (中略) 
        uid: libc::uid_t::from(unistd::Uid::current()),
        gid: libc::gid_t::from(unistd::Gid::current()),
// (中略) 
    }
}

libc::uid_t::fromとかやっているのは、Rustが型変換にも厳しくas u32でキャスティングできないので、一度uid_tとかの型にしてから……という手順を踏んでいるためです。

取得したuid/gidを聞かれたときに返せるようにする

まずファイルシステムのインスタンス作成時に属性を持てるように拡張します。

examples/hello.rs
struct HelloFS {
    pub attr: FileAttr, // 追加
}

このattrを初期化します。

examples/hello.rs
mod hello_attr;
    // (中略)
fn main() {
    // (中略)
    let hello_fs = HelloFS { attr : hello_attr::dir_attr_get() };
    fuse::mount(hello_fs, mountpoint, &options).unwrap();
}

これで属性を聞かれたときに答えられるようになります。

examples/hello.rs
    fn getattr(&mut self, _req: &Request, ino: u64, reply: ReplyAttr) {
        match ino {
            1 => reply.attr(&TTL, &(self.attr)), // ここを改造
            2 => reply.attr(&TTL, &HELLO_TXT_ATTR),
            _ => reply.error(ENOENT),
        }
    }

改造結果

> ls -ln /tmp
...
drwxrwxr-x 1 1000 1000    0  1月  1  1970 hello_dir
...

おわりに

今回はRust-FUSEを持ってきてサンプルコードの属性の返し方をちょっと改造してみたりしました。
属性ではino、たぶんinode番号を見てるっぽく、ここらへんに変な値を入れるとIOエラーになったりしました。ストレージが壊れるとそういう状況がナチュラルに起こるでしょうから、ファイルが壊れるってそういうことなのかとそのとき思いました。


今後はストレージにアクセスしてデータの不揮発化などに取り組んでいくつもりです。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0