noisebox/fuse.c

372 lines
10 KiB
C

#define FUSE_USE_VERSION 30
#define NOISER_COUNT 3
#include <errno.h>
#include <fuse.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "noisebox.h"
static void* do_init(struct fuse_conn_info *conn) {
struct nb_context *c = malloc(sizeof(struct nb_context));
Noiser** noisers = malloc(sizeof(Noiser*) * NOISER_COUNT);
noisers[0] = zero_init();
noisers[1] = mersenne_init();
noisers[2] = pcg_init();
c->noisers = noisers;
c->state_head = NULL;
return c;
}
static int getattr_root(struct stat *st) {
st->st_mode = S_IFDIR | 0755;
st->st_nlink = 2 + NOISER_COUNT;
printf("got attr?\n");
return 0;
}
static int lookup_path(const char *path, Noiser **n, NoiseFile **nf) {
struct fuse_context* c = fuse_get_context();
struct nb_context *nbc = c->private_data;
Noiser** noisers = nbc->noisers;
char* buf = strdup(path);
char *mod = strtok(buf, "/");
for(int i=0; i<NOISER_COUNT; i++) {
if(strcmp(mod, noisers[i]->name) == 0) {
*n = noisers[i];
}
}
if(!*n) {
printf("no noiser\n");
return -ENOENT;
}
char *fname = strtok(NULL, "/");
if(!fname) {
// we already had a valid noiser, so it's fine.
printf("returning noiser %p:%s, no fname\n", n, (*n)->name);
return 0;
}
for(int i=0; i<(*n)->noisefile_count; i++) {
if(strcmp(fname, (*n)->files[i]->name) == 0) {
*nf = (*n)->files[i];
}
}
if(*nf) {
printf("returning fname %p:%s\n", nf, (*nf)->name);
return 0;
} else {
printf("file not found: %s\n", fname);
return -ENOENT;
}
}
static int getattr_leaf(const char *path, struct stat *st) {
Noiser *n = NULL;
NoiseFile *nf = NULL;
int ret;
ret = lookup_path(path, &n, &nf);
if(ret !=0) {
return ret;
}
if(!n) {
printf("didn't find %s:%p\n", path, n);
return -EINVAL;
}
if(!nf) {
printf("return n, no nf\n");
st->st_mode = S_IFDIR | 0644;
st->st_nlink = 2 + n->noisefile_count;
printf("setup dir\n");
return 0;
}
printf("return n + nf: %p\n", nf);
st->st_mode = S_IFREG | 0644;
st->st_nlink = 1;
st->st_size = nf->size;
return 0;
}
static int do_getattr(const char *path, struct stat *st) {
st->st_uid = 0;
st->st_gid = 0;
// st->st_atime = __DATE__;
// st->st_mtime = __DATE__;
st->st_atime = time(NULL);
st->st_mtime = time(NULL);
int ret;
if(strcmp(path, "/") == 0) {
ret = getattr_root(st);
printf("got attr: root %i\n", ret);
} else {
ret = getattr_leaf(path, st);
};
return ret;
}
static void get_file_state(const char* path, struct fuse_file_info *fi) {
struct fuse_context *c = fuse_get_context();
struct nb_context *nbc = c->private_data;
struct file_state *fs = nbc->state_head;
if(!fs) {
printf("no state, it's fine.\n");
fi->fh = (uint64_t)NULL;
return;
}
while(fs->next) {
if(path == fs->name) {
fi->fh = (uint64_t)fs;
return;
}
fs = fs->next;
}
fi->fh = (uint64_t)NULL;
return;
}
static void append_file_state(struct file_state *add) {
struct fuse_context *c = fuse_get_context();
struct nb_context *nbc = c->private_data;
struct file_state *fs = nbc->state_head;
if(!fs) {
nbc->state_head = add;
return;
}
while(fs->next) {
fs = fs->next;
}
fs->next = add;
return;
}
// deletes from list, but does not free.
static void delete_file_state(struct file_state *del) {
struct fuse_context *c = fuse_get_context();
struct nb_context *nbc = c->private_data;
struct file_state *fs = nbc->state_head;
if(fs == del) {
printf("head = del\n");
if(del->next) {
fs = del->next;
} else {
fs = NULL;
}
return;
}
while(fs->next) {
if(del == fs->next) {
if(del->next) {
fs->next = del->next;
} else {
fs->next = NULL;
}
return;
}
fs = fs->next;
}
}
static int do_open(const char* path, struct fuse_file_info* fi) {
Noiser *n = NULL;
NoiseFile *nf = NULL;
int ret;
ret = lookup_path(path, &n, &nf);
if(ret !=0) {
printf("lookup_path() error");
return ret;
}
// check if file is already opened.
// never mind, we want to support multiple concurrent reads from
// the same file.
// get_file_state(path, fi);
// if(fi->fh) {
// return 0;
// }
if(n->do_open) {
ret = n->do_open(path, fi);
append_file_state((struct file_state *)fi->fh);
}
return ret;
}
static int do_release(const char *path, struct fuse_file_info *fi) {
Noiser *n = NULL;
NoiseFile *nf = NULL;
int ret;
ret = lookup_path(path, &n, &nf);
if(ret !=0) {
printf("lookup_path() error");
return ret;
}
if(fi->fh) {
printf("clearing from statelist\n");
delete_file_state((struct file_state *)fi->fh);
}
if(n->do_release) {
printf("noiser-specific cleanup\n");
ret = n->do_release(path, fi);
}
return ret;
}
static int do_read(const char* path, char* buf, size_t sz, off_t offset,
struct fuse_file_info* fi) {
int ret;
Noiser *n;
NoiseFile *nf;
ret = lookup_path(path, &n, &nf);
if(ret != 0) {
return ret;
}
ret = n->get_noise(sz, offset, buf, fi);
return ret;
}
static int readdir_root(void *buffer, fuse_fill_dir_t filler) {
struct fuse_context* c = fuse_get_context();
struct nb_context *nbc = c->private_data;
Noiser** noiser = nbc->noisers;
int ret = 0;
for(int i=0; i<NOISER_COUNT; i++) {
printf("filling noiser %i\n", i);
ret = filler(buffer, noiser[i]->name, NULL, 0);
if(ret != 0) {
printf("failed to fill %s, dying\n", noiser[i]->name);
break;
}
}
return ret;
}
static int do_noiser_readdir(const Noiser *n, const char *path, void *buffer,
fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi) {
NoiseFile **nfs = n->files;
int ret;
for(int i=0; i<n->noisefile_count; i++) {
printf("filling %i of %i: %s\n", i, n->noisefile_count, nfs[i]->name);
ret = filler(buffer, nfs[i]->name, NULL, 0);
if(ret != 0) {
break;
}
}
return ret;
}
static int do_readdir(const char *path, void *buffer,
fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi) {
filler(buffer, ".", NULL, 0);
filler(buffer, "..", NULL, 0);
int ret;
printf("doing readdir\n");
if(strcmp(path, "/") == 0) {
printf("calling readdir_root\n");
return readdir_root(buffer, filler);
}
// find noiser, generate appropriate files
Noiser *n = NULL;
NoiseFile *nf = NULL;
ret = lookup_path(path, &n, &nf);
if(ret !=0) {
printf("lookup_path() error");
return ret;
}
return do_noiser_readdir(n, path, buffer, filler, offset, fi);
}
static struct fuse_operations ops = {
// int (*getattr) (const char *, struct stat *);
.getattr = do_getattr,
// int (*readlink) (const char *, char *, size_t);
// int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t);
// int (*mknod) (const char *, mode_t, dev_t);
// int (*mkdir) (const char *, mode_t);
// int (*unlink) (const char *);
// int (*rmdir) (const char *);
// int (*symlink) (const char *, const char *);
// int (*rename) (const char *, const char *);
// int (*link) (const char *, const char *);
// int (*chmod) (const char *, mode_t);
// int (*chown) (const char *, uid_t, gid_t);
// int (*truncate) (const char *, off_t);
// int (*utime) (const char *, struct utimbuf *);
// int (*open) (const char *, struct fuse_file_info *);
.open = do_open,
// int (*read) (const char *, char *, size_t, off_t,
// struct fuse_file_info *);
.read = do_read,
// int (*write) (const char *, const char *, size_t, off_t,
// struct fuse_file_info *);
// int (*statfs) (const char *, struct statvfs *);
// int (*flush) (const char *, struct fuse_file_info *);
// int (*release) (const char *, struct fuse_file_info *);
.release = do_release,
// int (*fsync) (const char *, int, struct fuse_file_info *);
// int (*setxattr) (const char *, const char *, const char *, size_t, int);
// int (*getxattr) (const char *, const char *, char *, size_t);
// int (*listxattr) (const char *, char *, size_t);
// int (*removexattr) (const char *, const char *);
// int (*opendir) (const char *, struct fuse_file_info *);
// int (*readdir) (const char *, void *, fuse_fill_dir_t, off_t,
// struct fuse_file_info *);
.readdir = do_readdir,
// int (*releasedir) (const char *, struct fuse_file_info *);
// int (*fsyncdir) (const char *, int, struct fuse_file_info *);
// void *(*init) (struct fuse_conn_info *conn);
.init = do_init,
// void (*destroy) (void *);
// int (*access) (const char *, int);
// int (*create) (const char *, mode_t, struct fuse_file_info *);
// int (*ftruncate) (const char *, off_t, struct fuse_file_info *);
// int (*fgetattr) (const char *, struct stat *, struct fuse_file_info *);
// int (*lock) (const char *, struct fuse_file_info *, int cmd,
// struct flock *);
// int (*utimens) (const char *, const struct timespec tv[2]);
// int (*bmap) (const char *, size_t blocksize, uint64_t *idx);
// int (*ioctl) (const char *, int cmd, void *arg,
// struct fuse_file_info *, unsigned int flags, void *data);
// int (*poll) (const char *, struct fuse_file_info *,
// struct fuse_pollhandle *ph, unsigned *reventsp);
// int (*write_buf) (const char *, struct fuse_bufvec *buf, off_t off,
// struct fuse_file_info *);
// int (*read_buf) (const char *, struct fuse_bufvec **bufp,
// size_t size, off_t off, struct fuse_file_info *);
// int (*flock) (const char *, struct fuse_file_info *, int op);
// int (*fallocate) (const char *, int, off_t, off_t,
// struct fuse_file_info *);
.flag_nullpath_ok = 1,
};
int main(int argc, char* argv[]) {
return fuse_main(argc, argv, &ops, NULL);
}