FUSE 2でファイルシステムを作る 1
FUSE 2 でファイルシステムを作る方法について説明します.
実用的なファイルシステムよりは学習用,検証用になります.
概要
FUSE 2.9で、ファイルシステムを自作す方法を説明します.
読み込み可能なディレクトリ、読み込み可能なファイルを作ります.
環境
Debian 5.10.0-11
FUSE 2.9.9-5
インストール
apt -y install fuse libfuse-dev
ver. 0
何もしないファイルシステム
myfs.c
#define FUSE_USE_VERSION 29
#include <fuse.h>
static struct fuse_operations fuse_my_operations = {
};
int main(int argc, char *argv[])
{
return fuse_main(argc, argv, &fuse_my_operations, NULL);
}
コンパイル
もし
となってしまったら,
を忘れています.
もし
となってしまったら,
のを忘れています.
実行
rootで実行します
mkdir /mnt/a
./myfs -f /mnt/a
これでマウントされています.以下を別のターミナルでやってみましょう.
太字がユーザ入力
# mount | grep myfs
myfs on /mnt/a type fuse.myfs (rw,nosuid,nodev,relatime,user_id=0,group_id=0)
# cd /mnt/a
# ls
ls: cannot open directory '.': Function not implemented
マウントできるが,lsすらできない.
ver. 1
lsができるファイルシステム.
lsをできるようにするには,readdir() という「ディレクトリにあるファイル一覧を問い合わせる関数」などを作る必要があります.
そして,それら関数をfuseに登録します.
以下のreaddir()は . と .. のみを登録して返します.
#define FUSE_USE_VERSION 29
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fuse.h>
static int my_getattr(const char *path, struct stat *stbuf) {
printf("%s() path=%s\n", __func__, path);
if (strcmp(path, "/") == 0) {
stbuf->st_mode = S_IFDIR;
return 0;
}
return -ENOENT;
}
static int my_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi) {
printf("%s() path=%s offset=%ld\n", __func__, path, offset);
filler(buf, ".", NULL, 0);
filler(buf, "..", NULL, 0);
return 0;
}
static struct fuse_operations fuse_my_operations = {
.readdir = my_readdir,
.getattr = my_getattr,
};
int main(int argc, char *argv[])
{
return fuse_main(argc, argv, &fuse_my_operations, NULL);
}
readdir の関数と,getattr の関数のみを登録.
それらが呼び出されば場合は,printf() でdebugメッセージが表示される様になっている.
readdir は . と .. のみを返すようになっている.
getattr は,"/" に対する返答として,"ディレクトリである"ことだけ登録して,後はなにも登録していない.
コンパイル & 実行
別ターミナルで実行
lsの結果,
. と .. があることが分かる.
. (カレントディレクトリ)は,一切情報を登録していないので,タイムスタンプは1970/01/01の00時00分になっている.
ver. 2
lsができるファイルシステム.その2
ls をすると,ファイルが1個だけ得られるファイルシステムを作ります.
readdir() の結果は . と .. と hoge です.
#define FUSE_USE_VERSION 29
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fuse.h>
static int my_getattr(const char *path, struct stat *stbuf) {
printf("%s() path=%s\n", __func__, path);
memset(stbuf, 0, sizeof(struct stat));
if (strcmp(path, "/") == 0) {
stbuf->st_mode = S_IFDIR;
return 0;
} else if(strcmp(path, "/hoge") == 0) {
stbuf->st_mode = S_IFREG;
return 0;
}
return -ENOENT;
}
static int my_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi) {
printf("%s() path=%s offset=%ld\n", __func__, path, offset);
filler(buf, ".", NULL, 0);
filler(buf, "..", NULL, 0);
filler(buf, "hoge", NULL, 0);
return 0;
}
static struct fuse_operations fuse_my_operations = {
.readdir = my_readdir,
.getattr = my_getattr,
};
int main(int argc, char *argv[])
{
return fuse_main(argc, argv, &fuse_my_operations, NULL);
}
コンパイル & 実行
別ターミナルで実行
lsの結果,
. と .. と hoge があることが分かる.
ファイルパーミッションは 0 で,タイムスタンプも 0 (Unixタイムの0).
catコマンドでファイルの中身を読み込もうとしてもできない.
読み込むためには,read() 関数を実装する必要があります.
注意:getattr()の引数 path は "/hoge" で,
readdir()の中のfiller()に与えるのは"hoge"です.
ver. 2.1
lsができるファイルシステム.その3
ファイルのパーミション情報のみ提供してみる。
以下の修正を行います.
16c16
< stbuf->st_mode = S_IFREG;
---
> stbuf->st_mode = S_IFREG | 0754;
つまり
static int my_getattr(const char *path, struct stat *stbuf) {
printf("%s() path=%s\n", __func__, path);
memset(stbuf, 0, sizeof(struct stat));
if (strcmp(path, "/") == 0) {
stbuf->st_mode = S_IFDIR;
return 0;
} else if(strcmp(path, "/hoge") == 0) {
stbuf->st_mode = S_IFREG | 0754; /* ←ここだけ修正 */
return 0;
}
return -ENOENT;
}
実行
hogeというファイルのパーミションが -rwxr-xr-- になっている.
ver. 3
ファイルを読み込めるファイルシステム.
hoge という名のファイルがあり,
そのファイルを読み込めるファイルシステムを作ります.
#define FUSE_USE_VERSION 29
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fuse.h>
char txt[] = "hello, fuse!\n";
char filename[] = "/hoge";
static int my_getattr(const char *path, struct stat *stbuf) {
printf("%s() path=%s\n", __func__, path);
memset(stbuf, 0, sizeof(struct stat));
if (strcmp(path, "/") == 0) {
stbuf->st_mode = S_IFDIR;
return 0;
} else if(strcmp(path, filename) == 0) {
stbuf->st_mode = S_IFREG | 0754;
stbuf->st_size = strlen(txt);
return 0;
}
return -ENOENT;
}
static int my_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi) {
printf("%s() path=%s offset=%ld\n", __func__, path, offset);
filler(buf, ".", NULL, 0);
filler(buf, "..", NULL, 0);
filler(buf, filename+1, NULL, 0);
return 0;
}
static int my_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi) {
printf("%s() path=%s size=%ld offset=%ld\n", __func__, path, size, offset);
size_t len;
if (strcmp(path, filename) != 0) {
return -ENOENT;
}
len = strlen(txt);
if (offset >= len) {
return 0;
}
if (offset + size > len) {
size = (len - offset);
}
memcpy(buf, txt + offset, size);
return size;
}
static struct fuse_operations fuse_my_operations = {
.readdir = my_readdir,
.getattr = my_getattr,
.read = my_read,
};
int main(int argc, char *argv[])
{
return fuse_main(argc, argv, &fuse_my_operations, NULL);
}
コンパイル & 実行
別ターミナルで実行
cat hoge を実行すると,my_read() が呼ばれて,そこで設定された内容がプログラム(今回は cat)に返される.
リンク
FUSE 3.xでファイルシステムを作る 1