noisebox/fuse.c

267 lines
7.7 KiB
C

#define FUSE_USE_VERSION 30
#define NOISER_COUNT 2
#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) {
Noiser** noisers = malloc(sizeof(Noiser*) * NOISER_COUNT);
noisers[0] = zero_init();
noisers[1] = mersenne_init();
return noisers;
}
static int getattr_root(struct stat *st) {
st->st_mode = S_IFDIR | 0755;
st->st_nlink = 2 + NOISER_COUNT;
return 0;
}
static int lookup_path(const char *path, Noiser **n, NoiseFile **nf) {
struct fuse_context* c = fuse_get_context();
Noiser** noisers = c->private_data;
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);
} else {
ret = getattr_leaf(path, st);
};
return ret;
}
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) {
return ret;
}
ret = n->do_open(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();
Noiser** noiser = c->private_data;
int ret = 0;
for(int i=0; i<NOISER_COUNT; 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;
if(strcmp(path, "/") == 0) {
ret = readdir_root(buffer, filler);
} else {
// find noiser, generate appropriate files
struct fuse_context* c = fuse_get_context();
Noiser** noiser = c->private_data;
char * pathbuf = strdup(path);
char * toplevel = strtok(pathbuf, "/");
for(int i=0; i<NOISER_COUNT; i++) {
if(strcmp(noiser[i]->name, toplevel) == 0) {
printf("found noiser: %s\n", noiser[i]->name);
ret = do_noiser_readdir(noiser[i], path, buffer, filler,
offset, fi);
}
}
}
return ret;
}
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 *);
// 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);
}