1 下载FUSE
GitHub地址:https://github.com/libfuse/libfuse
在FUSE的GitHub页面上下载最新Release版本libfuse 3.8.0 https://github.com/libfuse/libfuse/archive/fuse-3.8.0.tar.gz
2 编译安装FUSE
2.1 编译准备工作
推荐使用Meson和ninja来编译安装FUSE。
sudo apt install ninja-build
sudo apt install meson
2.2 Meson预处理
git clone https://github.com/libfuse/libfuse.git
cd libfuse
mkdir build; cd build
meson
可以看到如下输出
sh@ubuntu:~/workspace/21cnbao/io-courses/fuse-hello/libfuse/build$ meson
The Meson build system
Version: 0.53.2
Source dir: /home/rlk/workspace/21cnbao/io-courses/fuse-hello/libfuse
Build dir: /home/rlk/workspace/21cnbao/io-courses/fuse-hello/libfuse/build
Build type: native build
Project name: libfuse3
Project version: 3.9.3
C compiler for the host machine: cc (gcc 9.3.0 "cc (Ubuntu 9.3.0-10ubuntu2) 9.3.0")
C linker for the host machine: cc ld.bfd 2.34
Host machine cpu family: x86_64
Host machine cpu: x86_64
Checking for function "fork" : YES
Checking for function "fstatat" : YES
Checking for function "openat" : YES
Checking for function "readlinkat" : YES
Checking for function "pipe2" : YES
Checking for function "splice" : YES
Checking for function "vmsplice" : YES
Checking for function "posix_fallocate" : YES
Checking for function "fdatasync" : YES
Checking for function "utimensat" : YES
Checking for function "copy_file_range" : YES
Checking for function "fallocate" : YES
Checking for function "setxattr" : YES
Checking for function "iconv" : YES
Checking whether type "struct stat" has member "st_atim" : YES
Checking whether type "struct stat" has member "st_atimespec" : NO
Configuring config.h using configuration
meson.build:66: WARNING: Consider using the built-in warning_level option instead of using "-Wall".
meson.build:66: WARNING: Consider using the built-in warning_level option instead of using "-Wextra".
meson.build:69: WARNING: Consider using the built-in warning_level option instead of using "-Wall".
meson.build:69: WARNING: Consider using the built-in warning_level option instead of using "-Wextra".
meson.build:69: WARNING: Consider using the built-in option for language standard version instead of using "-std=c++11".
Message: Compiler warns about unused result even when casting to void
Run-time dependency threads found: YES
Library iconv found: NO
Library dl found: YES
Library rt found: YES
Found pkg-config: /usr/bin/pkg-config (0.29.1)
Run-time dependency udev found: YES 245
Program install_helper.sh found: YES (/home/rlk/workspace/21cnbao/io-courses/fuse-hello/libfuse/util/install_helper.sh)
C++ compiler for the host machine: c++ (gcc 9.3.0 "c++ (Ubuntu 9.3.0-10ubuntu2) 9.3.0")
C++ linker for the host machine: c++ ld.bfd 2.34
Build targets in project: 26
Found ninja-1.10.0 at /usr/bin/ninja
2.3 使用Ninja来build,test和 install libfuse
ninja
sudo apt-get install python3-pip
sudo pip3 install pytest # 安装python3 的pytest模块
sudo python3 -m pytest test/
输出
sh@ubuntu:~/workspace/21cnbao/io-courses/fuse-hello/libfuse/build$ sudo python3 -m pytest test/
============================================================== test session starts ==============================================================
platform linux -- Python 3.8.2, pytest-6.0.1, py-1.9.0, pluggy-0.13.1 -- /usr/bin/python3
cachedir: .pytest_cache
rootdir: /home/rlk/workspace/21cnbao/io-courses/fuse-hello/libfuse/build/test, configfile: pytest.ini
collected 43 items
test/test_ctests.py::test_write_cache[False] PASSED [ 2%]
test/test_ctests.py::test_write_cache[True] PASSED [ 4%]
test/test_ctests.py::test_notify1[True-notify_inval_inode] PASSED [ 6%]
test/test_ctests.py::test_notify1[True-invalidate_path] PASSED [ 9%]
test/test_ctests.py::test_notify1[True-notify_store_retrieve] PASSED [ 11%]
test/test_ctests.py::test_notify1[False-notify_inval_inode] PASSED [ 13%]
test/test_ctests.py::test_notify1[False-invalidate_path] PASSED [ 16%]
test/test_ctests.py::test_notify1[False-notify_store_retrieve] PASSED [ 18%]
test/test_ctests.py::test_notify_file_size[True] PASSED [ 20%]
test/test_ctests.py::test_notify_file_size[False] PASSED [ 23%]
test/test_examples.py::test_hello[hello-options0-invoke_directly] PASSED [ 25%]
test/test_examples.py::test_hello[hello-options0-invoke_mount_fuse] PASSED [ 27%]
test/test_examples.py::test_hello[hello-options0-invoke_mount_fuse_drop_privileges] PASSED [ 30%]
test/test_examples.py::test_hello[hello-options1-invoke_directly] PASSED [ 32%]
test/test_examples.py::test_hello[hello-options1-invoke_mount_fuse] PASSED [ 34%]
test/test_examples.py::test_hello[hello-options1-invoke_mount_fuse_drop_privileges] PASSED [ 37%]
test/test_examples.py::test_hello[hello_ll-options0-invoke_directly] PASSED [ 39%]
test/test_examples.py::test_hello[hello_ll-options0-invoke_mount_fuse] PASSED [ 41%]
test/test_examples.py::test_hello[hello_ll-options0-invoke_mount_fuse_drop_privileges] PASSED [ 44%]
test/test_examples.py::test_hello[hello_ll-options1-invoke_directly] PASSED [ 46%]
test/test_examples.py::test_hello[hello_ll-options1-invoke_mount_fuse] PASSED [ 48%]
test/test_examples.py::test_hello[hello_ll-options1-invoke_mount_fuse_drop_privileges] PASSED [ 51%]
test/test_examples.py::test_passthrough[False-passthrough-False] PASSED [ 53%]
test/test_examples.py::test_passthrough[False-passthrough-True] SKIPPED [ 55%]
test/test_examples.py::test_passthrough[False-passthrough_fh-False] PASSED [ 58%]
test/test_examples.py::test_passthrough[False-passthrough_fh-True] SKIPPED [ 60%]
test/test_examples.py::test_passthrough[False-passthrough_ll-False] PASSED [ 62%]
test/test_examples.py::test_passthrough[False-passthrough_ll-True] PASSED [ 65%]
test/test_examples.py::test_passthrough[True-passthrough-False] PASSED [ 67%]
test/test_examples.py::test_passthrough[True-passthrough-True] SKIPPED [ 69%]
test/test_examples.py::test_passthrough[True-passthrough_fh-False] PASSED [ 72%]
test/test_examples.py::test_passthrough[True-passthrough_fh-True] SKIPPED [ 74%]
test/test_examples.py::test_passthrough[True-passthrough_ll-False] PASSED [ 76%]
test/test_examples.py::test_passthrough[True-passthrough_ll-True] PASSED [ 79%]
test/test_examples.py::test_passthrough_hp[False] PASSED [ 81%]
test/test_examples.py::test_passthrough_hp[True] PASSED [ 83%]
test/test_examples.py::test_ioctl PASSED [ 86%]
test/test_examples.py::test_poll PASSED [ 88%]
test/test_examples.py::test_null PASSED [ 90%]
test/test_examples.py::test_notify_inval_entry[True] PASSED [ 93%]
test/test_examples.py::test_notify_inval_entry[False] PASSED [ 95%]
test/test_examples.py::test_cuse PASSED [ 97%]
test/test_examples.py::test_printcap PASSED [100%]
=============================================================== warnings summary ================================================================
test/util.py:132
test/util.py:132
/home/rlk/workspace/21cnbao/io-courses/fuse-hello/libfuse/build/test/util.py:132: PytestUnknownMarkWarning: Unknown pytest.mark.uses_fuse - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html
return pytest.mark.uses_fuse()
-- Docs: https://docs.pytest.org/en/stable/warnings.html
============================================================ short test summary info============================================================
SKIPPED [4] test/test_examples.py:126: example does not support writeback caching
最后安装
sh@ubuntu:~/workspace/21cnbao/io-courses/fuse-hello/libfuse/build$ sudo ninja install
[0/1] Installing files.
Installing lib/libfuse3.so.3.9.3 to /usr/local/lib/x86_64-linux-gnu
Installing util/fusermount3 to /usr/local/bin
Installing util/mount.fuse3 to /usr/local/sbin
Installing /home/rlk/workspace/21cnbao/io-courses/fuse-hello/libfuse/include/fuse.h to /usr/local/include/fuse3
Installing /home/rlk/workspace/21cnbao/io-courses/fuse-hello/libfuse/include/fuse_common.h to /usr/local/include/fuse3
Installing /home/rlk/workspace/21cnbao/io-courses/fuse-hello/libfuse/include/fuse_lowlevel.h to /usr/local/include/fuse3
Installing /home/rlk/workspace/21cnbao/io-courses/fuse-hello/libfuse/include/fuse_opt.h to /usr/local/include/fuse3
Installing /home/rlk/workspace/21cnbao/io-courses/fuse-hello/libfuse/include/cuse_lowlevel.h to /usr/local/include/fuse3
Installing /home/rlk/workspace/21cnbao/io-courses/fuse-hello/libfuse/include/fuse_log.h to /usr/local/include/fuse3
Installing /home/rlk/workspace/21cnbao/io-courses/fuse-hello/libfuse/doc/fusermount3.1 to /usr/local/share/man/man1
Installing /home/rlk/workspace/21cnbao/io-courses/fuse-hello/libfuse/doc/mount.fuse3.8 to /usr/local/share/man/man8
Installing /home/rlk/workspace/21cnbao/io-courses/fuse-hello/libfuse/build/meson-private/fuse3.pc to /usr/local/lib/x86_64-linux-gnu/pkgconfig
Running custom install script '/home/rlk/workspace/21cnbao/io-courses/fuse-hello/libfuse/util/install_helper.sh /usr/local/etc /usr/local/bin /lib/udev/rules.d true'
update-rc.d: warning: start and stop actions are no longer supported; falling back to defaults
update-rc.d: warning: stop runlevel arguments (0 6) do not match fuse3 Default-Stop values (none)
3 测试hello.c例程文件系统
FUSE的example目录下自带了许多测试文件系统,其中最简单文件系统hello.c使用了high-level API,我们以此来测试FUSE是否安装成功。
源码如下:
/*
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.
*/
/** @file
*
* minimal example filesystem using high-level API
*
* Compile with:
*
* gcc -Wall hello.c `pkg-config fuse3 --cflags --libs` -o hello
*
* ## Source code ##
* \include hello.c
*/
#define FUSE_USE_VERSION 31
#include <fuse.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <stddef.h>
#include <assert.h>
/*
* Command line options
*
* We can't set default values for the char* fields here because
* fuse_opt_parse would attempt to free() them when the user specifies
* different values on the command line.
*/
static struct options {
const char *filename;
const char *contents;
int show_help;
} options;
#define OPTION(t, p) \
{ t, offsetof(struct options, p), 1 }
static const struct fuse_opt option_spec[] = {
OPTION("--name=%s", filename),
OPTION("--contents=%s", contents),
OPTION("-h", show_help),
OPTION("--help", show_help),
FUSE_OPT_END
};
static void *hello_init(struct fuse_conn_info *conn,
struct fuse_config *cfg)
{
(void) conn;
cfg->kernel_cache = 1;
return NULL;
}
static int hello_getattr(const char *path, struct stat *stbuf,
struct fuse_file_info *fi)
{
(void) fi;
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+1, options.filename) == 0) {
stbuf->st_mode = S_IFREG | 0444;
stbuf->st_nlink = 1;
stbuf->st_size = strlen(options.contents);
} else
res = -ENOENT;
return res;
}
static int hello_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
off_t offset, struct fuse_file_info *fi,
enum fuse_readdir_flags flags)
{
(void) offset;
(void) fi;
(void) flags;
if (strcmp(path, "/") != 0)
return -ENOENT;
filler(buf, ".", NULL, 0, 0);
filler(buf, "..", NULL, 0, 0);
filler(buf, options.filename, NULL, 0, 0);
return 0;
}
static int hello_open(const char *path, struct fuse_file_info *fi)
{
if (strcmp(path+1, options.filename) != 0)
return -ENOENT;
if ((fi->flags & O_ACCMODE) != O_RDONLY)
return -EACCES;
return 0;
}
static int hello_read(const char *path, char *buf, size_t size, off_t offset,
struct fuse_file_info *fi)
{
size_t len;
(void) fi;
if(strcmp(path+1, options.filename) != 0)
return -ENOENT;
len = strlen(options.contents);
if (offset < len) {
if (offset + size > len)
size = len - offset;
memcpy(buf, options.contents + offset, size);
} else
size = 0;
return size;
}
static struct fuse_operations hello_oper = {
.init = hello_init,
.getattr = hello_getattr,
.readdir = hello_readdir,
.open = hello_open,
.read = hello_read,
};
static void show_help(const char *progname)
{
printf("usage: %s [options] <mountpoint>\n\n", progname);
printf("File-system specific options:\n"
" --name=<s> Name of the \"hello\" file\n"
" (default: \"hello\")\n"
" --contents=<s> Contents \"hello\" file\n"
" (default \"Hello, World!\\n\")\n"
"\n");
}
int main(int argc, char *argv[])
{
int ret;
struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
/* Set defaults -- we have to use strdup so that
fuse_opt_parse can free the defaults if other
values are specified */
options.filename = strdup("hello");
options.contents = strdup("Hello World!\n");
/* Parse options */
if (fuse_opt_parse(&args, &options, option_spec, NULL) == -1)
return 1;
/* When --help is specified, first print our own file-system
specific help text, then signal fuse_main to show
additional help (by adding `--help` to the options again)
without usage: line (by setting argv[0] to the empty
string) */
if (options.show_help) {
show_help(argv[0]);
assert(fuse_opt_add_arg(&args, "--help") == 0);
args.argv[0][0] = '\0';
}
ret = fuse_main(args.argc, args.argv, &hello_oper, NULL);
fuse_opt_free_args(&args);
return ret;
}
从hello.c的注释中我们可以看到gcc编译方式:
sh@ubuntu:~/workspace/21cnbao/io-courses/fuse-hello/libfuse/example$ gcc -Wall hello.c `pkg-config fuse3 --cflags --libs` -o hello
sh@ubuntu:~/workspace/21cnbao/io-courses/fuse-hello/libfuse/example$ mkdir hello_test
mkdir: cannot create directory ‘hello_test’: File exists
sh@ubuntu:~/workspace/21cnbao/io-courses/fuse-hello/libfuse/example$ gcc -Wall hello.c `pkg-config fuse3 --cflags --libs` -o hello
sh@ubuntu:~/workspace/21cnbao/io-courses/fuse-hello/libfuse/example$ mkdir hello_test -p
sh@ubuntu:~/workspace/21cnbao/io-courses/fuse-hello/libfuse/example$ ./hello hello_test/
sh@ubuntu:~/workspace/21cnbao/io-courses/fuse-hello/libfuse/example$ mount |grep hello
/home/rlk/workspace/21cnbao/io-courses/fuse-hello/libfuse/example/hello on /home/rlk/workspace/21cnbao/io-courses/fuse-hello/libfuse/example/hello_test type fuse.hello (rw,nosuid,nodev,relatime,user_id=1000,group_id=1000)
sh@ubuntu:~/workspace/21cnbao/io-courses/fuse-hello/libfuse/example$ umount hello_test
sh@ubuntu:~/workspace/21cnbao/io-courses/fuse-hello/libfuse/example$ mount |grep hello
4 分析hello文件系统
。。。。