データ生成
[Linux] FUSEを使ってみようではFUSEを使って、ファイルシステムとしてマウントする例を見たけど、今度はFUSEを使ってデータを生成するファイルを作ってみよう。開発用のヘッダファイルとかが必要になるので、https://github.com/libfuseからライブラリを入手するか、fuse-developパッケージをインストールしよう。
今回はfuse 2.9.3を使用した。
0を生成し続ける
例えば、/dev/zeroのようにひたすら0を生成し続けるファイルを作りたければ以下のようにすればいい。/dev/zeroとは違って、null文字ではなく、文字の'0'を生成するようにしてみよう。
今回はFUSEのサンプルプログラムであるhello.cをコピーして、これを元にした。
ちなみに、サンプルプログラム(hello.c)はGPLだけど、libfuse自体はLGPLなので、libfuseを使っているからといって自分のプログラムをGPLにしなければいけないわけではない。
zero.c
/* Copyright (C) 2017 Takehiko Ichioka <ichioka.takehiko@gmail.com> based on code by FUSE: Filesystem in Userspace Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu> This program can be distributed under the terms of the GNU GPL. See the file COPYING. gcc -Wall zero.c `pkg-config fuse --cflags --libs` -o zero */ #define FUSE_USE_VERSION 26 #include <fuse.h> #include <stdio.h> #include <string.h> #include <errno.h> #include <fcntl.h> static const char *zero_path = "/zero"; static int zero_getattr(const char *path, struct stat *stbuf) { int res = 0; memset(stbuf, 0, sizeof(struct stat)); if (strcmp(path, "/") == 0) { stbuf->st_mode = S_IFDIR | 0755; stbuf->st_nlink = 2; } else if (strcmp(path, zero_path) == 0) { stbuf->st_mode = S_IFREG | 0444; stbuf->st_nlink = 1; stbuf->st_size = 0; } else res = -ENOENT; return res; } static int zero_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi) { (void) offset; (void) fi; if (strcmp(path, "/") != 0) return -ENOENT; filler(buf, ".", NULL, 0); filler(buf, "..", NULL, 0); filler(buf, zero_path + 1, NULL, 0); return 0; } static int zero_open(const char *path, struct fuse_file_info *fi) { if (strcmp(path, zero_path) != 0) return -ENOENT; if ((fi->flags & 3) != O_RDONLY) return -EACCES; return 0; } static int zero_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi) { (void) fi; if(strcmp(path, zero_path) != 0) return -ENOENT; memset(buf, '0', size); return size; } static struct fuse_operations zero_oper = { .getattr = zero_getattr, .readdir = zero_readdir, .open = zero_open, .read = zero_read, }; int main(int argc, char *argv[]) { return fuse_main(argc, argv, &zero_oper, NULL); }
基本的には前述のhello.cと同じになる。
hello_read関数が呼ばれると、とにかくバッファサイズ分'0'を詰めているのが異なるところだ。
コンパイル&実行
これをコンパイルして、実行するとmntディレクトリにzeroファイルが見えるようになる。$ gcc -Wall zero.c $(pkg-config fuse --cflags --libs) -o zero $ ls -l mnt total 0 $ ./zero -o direct_io mnt $ ls -l mnt total 0 -r--r--r-- 1 root root 0 Jan 1 1970 zero
ポイントは実行時に -o direct_io オプションをつけていること。
これをつけないと、zeroファイル読み込み時にファイルサイズが0と判定されて、1バイトも読み込まれずに終了してしまう。
これで、10文字分'0'を読み込みたければ、以下のようにすればいい。
$ cat mnt/zero | head -c10 0000000000$
これをうまく使えば、ファイル読み込みを適度に遅延させたり、ログ出力をシミュレートすることもできそうだね。
0 件のコメント:
コメントを投稿