This example implements a file system with a single file whose contents change dynamically: it always contains the current time.
Observe that the output never changes, even though the file system updates it once per second. This is because the contents are cached in the kernel:
#define FUSE_USE_VERSION 31
#include <fuse_lowlevel.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <assert.h>
#include <stddef.h>
#include <unistd.h>
#include <pthread.h>
#define NO_TIMEOUT 500000
#define ACCESS_MASK (O_RDONLY | O_WRONLY | O_RDWR)
#define MAX_STR_LEN 128
#define FILE_INO 2
#define FILE_NAME "current_time"
static char file_contents[MAX_STR_LEN];
static int lookup_cnt = 0;
static size_t file_size;
struct options {
int no_notify;
int update_interval;
};
static struct options options = {
.no_notify = 0,
.update_interval = 1,
};
#define OPTION(t, p) \
{ t, offsetof(struct options, p), 1 }
static const struct fuse_opt option_spec[] = {
OPTION("--no-notify", no_notify),
OPTION("--update-interval=%d", update_interval),
};
static int tfs_stat(
fuse_ino_t ino,
struct stat *stbuf) {
stbuf->st_ino = ino;
stbuf->st_mode = S_IFDIR | 0755;
stbuf->st_nlink = 1;
}
else if (ino == FILE_INO) {
stbuf->st_mode = S_IFREG | 0444;
stbuf->st_nlink = 1;
stbuf->st_size = file_size;
}
else
return -1;
return 0;
}
const char *name) {
memset(&e, 0, sizeof(e));
goto err_out;
else if (strcmp(name, FILE_NAME) == 0) {
e.ino = FILE_INO;
lookup_cnt++;
} else
goto err_out;
e.attr_timeout = NO_TIMEOUT;
e.entry_timeout = NO_TIMEOUT;
if (tfs_stat(e.ino, &e.attr) != 0)
goto err_out;
return;
err_out:
}
uint64_t nlookup) {
(void) req;
if(ino == FILE_INO)
lookup_cnt -= nlookup;
else
}
struct stat stbuf;
(void) fi;
memset(&stbuf, 0, sizeof(stbuf));
if (tfs_stat(ino, &stbuf) != 0)
else
}
struct dirbuf {
char *p;
size_t size;
};
static void dirbuf_add(
fuse_req_t req,
struct dirbuf *b,
const char *name,
struct stat stbuf;
size_t oldsize = b->size;
b->p = (char *) realloc(b->p, b->size);
memset(&stbuf, 0, sizeof(stbuf));
stbuf.st_ino = ino;
b->size);
}
#define min(x, y) ((x) < (y) ? (x) : (y))
static int reply_buf_limited(
fuse_req_t req,
const char *buf,
size_t bufsize,
off_t off, size_t maxsize) {
if (off < bufsize)
min(bufsize - off, maxsize));
else
}
(void) fi;
else {
struct dirbuf b;
memset(&b, 0, sizeof(b));
dirbuf_add(req, &b, FILE_NAME, FILE_INO);
reply_buf_limited(req, b.p, b.size, off, size);
free(b.p);
}
}
else if ((fi->
flags & ACCESS_MASK) != O_RDONLY)
else if (ino == FILE_INO)
else {
fprintf(stderr, "Got open for non-existing inode!\n");
}
}
(void) fi;
assert(ino == FILE_INO);
reply_buf_limited(req, file_contents, file_size, off, size);
}
.getattr = tfs_getattr,
.readdir = tfs_readdir,
.open = tfs_open,
.read = tfs_read,
.forget = tfs_forget,
};
static void update_fs(void) {
struct tm *now;
time_t t;
t = time(NULL);
now = localtime(&t);
assert(now != NULL);
file_size = strftime(file_contents, MAX_STR_LEN,
"The current time is %H:%M:%S\n", now);
assert(file_size != 0);
}
static void* update_fs_loop(void *data) {
struct fuse_session *se = (struct fuse_session*) data;
while(1) {
update_fs();
if (!options.no_notify && lookup_cnt) {
(se, FILE_INO, 0, 0) == 0);
}
sleep(options.update_interval);
}
return NULL;
}
static void show_help(const char *progname)
{
printf("usage: %s [options] <mountpoint>\n\n", progname);
printf("File-system specific options:\n"
" --update-interval=<secs> Update-rate of file system contents\n"
" --no-notify Disable kernel notifications\n"
"\n");
}
int main(int argc, char *argv[]) {
struct fuse_session *se;
struct fuse_cmdline_opts opts;
pthread_t updater;
int ret = -1;
return 1;
ret = 1;
goto err_out1;
}
if (opts.show_help) {
show_help(argv[0]);
ret = 0;
goto err_out1;
} else if (opts.show_version) {
ret = 0;
goto err_out1;
}
update_fs();
sizeof(tfs_oper), NULL);
if (se == NULL)
goto err_out1;
goto err_out2;
goto err_out3;
ret = pthread_create(&updater, NULL, update_fs_loop, (void *)se);
if (ret != 0) {
fprintf(stderr, "pthread_create failed with %s\n",
strerror(ret));
goto err_out3;
}
if (opts.singlethread)
else
ret = fuse_session_loop_mt(se, opts.clone_fd);
err_out3:
err_out2:
err_out1:
free(opts.mountpoint);
return ret ? 1 : 0;
}