当前位置:首页>Linux>Linux下使用fuse编写文件系统(3)

Linux下使用fuse编写文件系统(3)

  • 2026-08-24 11:21:45
Linux下使用fuse编写文件系统(3)
在 《Linux下使用fuse编写文件系统(1)、(2)》中,我们在Linux环境上使用fuse编写了oufs文件系统,支持列表、创建和删除文件操作,接下来在该基础上增加读写文件操作:
#define FUSE_USE_VERSION 26#include<stdio.h>#include<string.h>#include<errno.h>#include<fuse.h>#define BUFFSIZE 8192static int content_size;static char content[BUFFSIZE];static const char* fname = "hello-world";staticintou_readdir(constchar* path, void* buf, fuse_fill_dir_t filler,                      off_t offset, struct fuse_file_info* fi){    return filler(buf, fname, NULL, 0);}staticintou_getattr(constchar* path, struct stat* st){    memset(st, 0, sizeof(struct stat));    if (strcmp(path, "/") == 0) {        st->st_mode = 0755 | S_IFDIR;        st->st_size = strlen(fname);    } else {        st->st_mode = 0644 | S_IFREG;        st->st_size = content_size;    }    return 0;}staticintou_read(constchar* path, char* buf, size_t bytes, off_t offset,                   struct fuse_file_info* fi){    size_t available;    if (strcmp(path + 1, fname) != 0)        return -ENOENT;    if (offset >= content_size)        return 0;    available = content_size - offset;    if (available < bytes)        bytes = available;    memcpy(buf, content + offset, bytes);    return bytes;}staticintou_write(constchar* path, constchar* buf, size_t bytes,                    off_t offset, struct fuse_file_info* fi){    size_t new_size;    if (strcmp(path + 1, fname) != 0)        return -ENOENT;    new_size = offset + bytes;    if (new_size > BUFFSIZE)        return -EFBIG;    memcpy(content + offset, buf, bytes);    if (content_size < new_size)        content_size = new_size;    return bytes;}staticintou_truncate(constchar* path, off_t size){    if (size > BUFFSIZE)        return -EFBIG;    if (content_size < size)        memset(content + content_size, 0, size - content_size);    content_size = size;    return 0;}static struct fuse_operations oufs_ops = {    .readdir    =   ou_readdir,    .getattr    =   ou_getattr,    .read       =   ou_read,    .write      =   ou_write,    .truncate   =   ou_truncate,};intmain(int argc, char* argv[]){    return fuse_main(argc, argv, &oufs_ops, NULL);}

我们使用一个全局缓冲区content用来记录hello-world的内容,content_size用来记录缓冲区长度。函数ou_read()和ou_write()分别用来读写hello-world的内容,ou_truncate() 用来改变文件大小。这些函数的功能不具体描述了,manpage 里面说得很详细。

接下来,我们再新增创建、删除目录功能:

#define FUSE_USE_VERSION 26#include<stdio.h>#include<stdlib.h>#include<string.h>#include<errno.h>#include<fuse.h>#include"list.h"#define MAX_NAMELEN 255struct ou_entry {    mode_t mode;    struct list_node node;    char name[MAX_NAMELEN + 1];};static struct list_node entries;staticintou_readdir(constchar* path, void* buf, fuse_fill_dir_t filler,                      off_t offset, struct fuse_file_info* fi){    struct list_node* n;    if (strcmp(path, "/") != 0)        return -EINVAL;    filler(buf, ".", NULL, 0);    filler(buf, "..", NULL, 0);    list_for_each (n, &entries) {        struct ou_entry* o = list_entry(n, struct ou_entry, node);        filler(buf, o->name, NULL, 0);    }    return 0;}staticintou_getattr(constchar* path, struct stat* st){    struct list_node* n;    memset(st, 0, sizeof(struct stat));    if (strcmp(path, "/") == 0) {        st->st_mode = 0755 | S_IFDIR;        st->st_nlink = 2;        st->st_size = 0;        list_for_each (n, &entries) {            struct ou_entry* o = list_entry(n, struct ou_entry, node);            ++st->st_nlink;            st->st_size += strlen(o->name);        }        return 0;    }    list_for_each (n, &entries) {        struct ou_entry* o = list_entry(n, struct ou_entry, node);        if (strcmp(path + 1, o->name) == 0) {            st->st_mode = o->mode;            st->st_nlink = 2;            return 0;        }    }    return -ENOENT;}staticintou_mkdir(constchar* path, mode_t mode){    struct ou_entry* o;    struct list_node* n;    if (strlen(path + 1) > MAX_NAMELEN)        return -ENAMETOOLONG;    list_for_each (n, &entries) {        o = list_entry(n, struct ou_entry, node);        if (strcmp(path + 1, o->name) == 0)            return -EEXIST;    }    o = malloc(sizeof(struct ou_entry));    strcpy(o->name, path + 1); /* skip the leading '/' */    o->mode = mode | S_IFDIR;    list_add_prev(&o->node, &entries);    return 0;}staticintou_rmdir(constchar* path){    struct list_node *n, *p;    if (strcmp(path, "/") != 0)        return -EINVAL;    list_for_each_safe (n, p, &entries) {        struct ou_entry* o = list_entry(n, struct ou_entry, node);        if (strcmp(path + 1, o->name) == 0) {            __list_del(n);            free(o);            return 0;        }    }    return -ENOENT;}static struct fuse_operations oufs_ops = {    .getattr    =   ou_getattr,    .readdir    =   ou_readdir,    .mkdir      =   ou_mkdir,    .rmdir      =   ou_rmdir,};intmain(int argc, char* argv[]){    list_init(&entries);    return fuse_main(argc, argv, &oufs_ops, NULL);}

为了防止对新建的目录执行ls得到错误的结果,程序里把所有函数的执行目录都限定在根目录下。和创建/删除文件的程序比较一下,除了把create()/unlink()分别替换成mkdir()/rmdir()外其它内容基本没有变化,使用的还是同样的数据结构。在linux vfs的实现中目录的确是被作为一个特殊的文件对待,只是普通文件使用read()/write()访问,而目录使用readdir()/mkdir()访问。

最新文章

随机文章