Sunday | 23 JUN 2024
[ previous ]
[ next ]

FUSE Tutorial - 02 Getting Started

Title:
Date: 2023-02-01
Tags:  

Time for the easiest step! Let's compile a simple program that includes fuse.

Create a directory to house our project and then create a sfs.c that contains the following:

#define FUSE_USE_VERSION 29
#include <fuse.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

static struct fuse_operations sfs_ops = {
};

int main(int argc, char **argv)
{
    int i;

    for (i = 1; i < argc && argv[i][0] == '-'; i++);
    if (i < argc) {
        memcpy(&argv[i], &argv[i+1], (argc-i) * sizeof(argv[0]));
        argc--;
    }

    printf("Lighting FUSE...\n");
    return fuse_main(argc, argv, &sfs_ops, NULL);
}

The reason we use the sfs_ naming is so that we don't overwrite functions that may have been defined in one of the included header files. Ask me how I learned that.

The core idea is that we include fuse.h and we then pass the commandline arguments wholesale to fuse_main. fuse_main is what will handle the file system calls.

Now the core of the core is that we pass in ops to fuse_main. Presumably fuse_main will use ops to overwrite various operations we define. For example if the readdir operation is written and added to our ops, then this function will overwrite the real readdir inside fuse_main. It's a really cool way of allow modifications to a core system like the file system.

I've seen this before but I just can't place where. This pattern is so comfortable that I'm sure I've used it all over the place. Something like python's magic functions.

Anyway, now that we have a basic fuse program, let's compile it and run it.

To compile:

gcc -lfuse -D_FILE_OFFSET_BITS=64 sfs.c -o sfs

In case it's relevant, my gcc version:

gcc version 4.8.5 20150623 (Red Hat 4.8.5-44) (GCC)

We should now have a binary called sfs in our folder. Before we try using it lets create a sqlite file as that is what we will be trying to expose as a file system and a directory that we can mount it to.

Create the database:

sqlite3 db.sqlite

Create a simple table and some dummy data:

create table mytable(title primary key,body);
insert into mytable (title,body) values ("Post 1", "Content in post 1.");
insert into mytable (title,body) values ("Post 2", "Content in post 2.");

Create the folder that we will mount to:

mkdir dir 

We can now mount our sqlite file to our folder:

./sfs -f db.sqlite dir

You can use the -d flag to get debug information. The -f is to run the mount in the foreground. This is all so we can see what fuse is doing when it mounts our sqlite file to our folder.

Now we should see the following output:

./sfs -d -f -s db.sqlite dir 
Lighting FUSE...

In another terminal we can cd into our working directory and then we can do ls -l to view die

This should give us the following:

ls -l
d????????? ? ?        ?           ?            ? dir/

If we did ls dir/, we will see:

ls dir
ls: reading directory dir: Function not implemented

Voila! With that we now have a working fuse program that mounts our sqlite database as a folder. It doesn't do anything yet but it will!