370 lines
10 KiB
C
370 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.
|
|
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);
|
|
}
|