commit b5a5a3a931e9d13a8f66e3d5f9bf97e6ff7f13b9 Author: chris t Date: Sun Sep 13 08:45:36 2020 -0700 initial commit -- works, but needs features. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..84501ae --- /dev/null +++ b/Makefile @@ -0,0 +1,17 @@ +CC = gcc +CFLAGS = -g `pkg-config fuse --cflags --libs` + +DEPS = noisebox.h +OBJ = fuse.o zeroes.o mersenne.o + +%.o: %.c $(DEPS) + $(CC) -c -o $@ $< $(CFLAGS) + +noisebox: $(OBJ) + $(CC) -o $@ $^ $(CFLAGS) + +.PHONY: clean + +clean: + rm -f *.o + rm -f noisebox diff --git a/README b/README new file mode 100644 index 0000000..5e8c43d --- /dev/null +++ b/README @@ -0,0 +1 @@ +noisebox -- a FUSE filesystem that contains predictable PRNG output. diff --git a/fuse.c b/fuse.c new file mode 100644 index 0000000..e37ae59 --- /dev/null +++ b/fuse.c @@ -0,0 +1,266 @@ +#define FUSE_USE_VERSION 30 +#define NOISER_COUNT 2 + +#include +#include +#include +#include +#include +#include +#include + +#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; iname) == 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; iname, 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; inoisefile_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; iname, 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); +} diff --git a/mersenne.c b/mersenne.c new file mode 100644 index 0000000..81eaf26 --- /dev/null +++ b/mersenne.c @@ -0,0 +1,161 @@ +/* + * mersenne.c -- component to provide random numbers on demand. + */ + +#include +#include +#include +#include + +#include "noisebox.h" + +enum { + // assumes W = 32 + N = 624, + M = 397, + R = 31, + A = 0x9908B0DF, + + F = 1812433253, + + U = 11, + // assumes D = 0xFFFFFFFF + + S = 7, + B = 0x9D2C5680, + T = 15, + C = 0xEFC60000, + + L = 18, + + MASK_LOWER = (1ull << R) -1, + MASK_UPPER = (1ull << R), +}; + + +// state for single generator. +struct mt_state { + uint32_t mt[N]; + int index; + off_t begin; + size_t consumed; + char overflow[4]; + int overflow_len; +}; + + +static void twist(struct mt_state *state) { + uint32_t i, x, xA; + uint32_t *mt = state->mt; + + for(i=0; i> 1; + + if(x & 0x1) xA ^= A; + + mt[i] = mt[(i+M) % N] ^ xA; + } + + state->index = 0; +} + +static void mt_init(struct mt_state *state, const uint32_t seed) { + uint32_t i; + uint32_t *mt = state->mt; + mt[0] = seed; + + for(i=1; i> 30)) + i); + } + + twist(state); +} + +static uint32_t extract_u32(struct mt_state *state) { + uint32_t y; + + if(state->index >= N) { + twist(state); + } + + int i = state->index; + + y = state->mt[i]; + state->index++; + + y ^= (y >> U); + y ^= (y << S) & B; + y ^= (y << T) & C; + y ^= (y >> L); + + return y; +} + + +static int do_open(const char *path, struct fuse_file_info *fi) { + struct mt_state *state = malloc(sizeof(struct mt_state)); + mt_init(state, 0); + + fi->fh = (uint64_t)state; + return 0; +} + +static int do_getattr(const char *path, struct stat *st) { +} + + +static int get_noise(size_t n, off_t offset, char* buf, + struct fuse_file_info *fi) { + printf("getting random bits: %i@%i (%i)\n", n, offset, n*sizeof(char)); + uint32_t *tmp = malloc(n * sizeof(char)); + printf("allocated %i\n", sizeof(char) * n); + + struct mt_state *state = (struct mt_state *)(fi->fh); + + float buf_ratio = (float)sizeof(char)/(float)sizeof(uint32_t); + int count = n * buf_ratio; + printf("calling extract_u32 %i times (%i * %f)\n", count, n, buf_ratio); + for(int i=0; iconsumed, count); + state->consumed += count; + printf("wrote buf\n"); + memcpy(buf, tmp, n); + free(tmp); + return n; +} + +Noiser* mersenne_init(void) { + Noiser* n = malloc(sizeof(Noiser)); + n->name = "mersenne"; + n->get_noise = get_noise; + n->do_open = do_open; + + n->noisefile_count = 5; + n->files = malloc(sizeof(NoiseFile *) * n->noisefile_count); + + n->files[0] = malloc(sizeof(NoiseFile)); + n->files[0]->name = "1M"; + n->files[0]->size = 1ULL<<20; + + n->files[1] = malloc(sizeof(NoiseFile)); + n->files[1]->name = "1G"; + n->files[1]->size = 1ULL<<30; + + n->files[2] = malloc(sizeof(NoiseFile)); + n->files[2]->name = "100G"; + n->files[2]->size = 100 * (1ULL<<30); + + n->files[3] = malloc(sizeof(NoiseFile)); + n->files[3]->name = "200G"; + n->files[3]->size = 200 * (1ULL<<30); + + n->files[4] = malloc(sizeof(NoiseFile)); + n->files[4]->name = "400G"; + n->files[4]->size = 400 * (1ULL<<30); + + return n; +} diff --git a/noisebox.h b/noisebox.h new file mode 100644 index 0000000..7325b42 --- /dev/null +++ b/noisebox.h @@ -0,0 +1,33 @@ +/* + * noisebox.h -- interfaces for noise provision. + */ + +#include +#include + +#ifndef NOISEBOX_H +#define NOISEBOX_H + +typedef struct { + char *name; + uint64_t size; +} NoiseFile; + +typedef struct { + char* name; + void *state; + + int noisefile_count; + NoiseFile **files; + + int (*get_noise)(size_t, off_t, char*, struct fuse_file_info *); + + // int (*do_readdir)(const char *path, void *buffer, fuse_fill_dir_t filler, + // off_t offset, struct fuse_file_info *fi); + int (*do_open)(const char *, struct fuse_file_info *); +} Noiser; + +Noiser* zero_init(void); +Noiser* mersenne_init(void); + +#endif diff --git a/random.c b/random.c new file mode 100644 index 0000000..8a4b398 --- /dev/null +++ b/random.c @@ -0,0 +1,95 @@ +/* + * random.c -- prng whatnot. + * + * mersenne twister implementation from wikipedia, via + * https://github.com/bmurray7/mersenne-twister-examples/ + */ + +#include +#include + +// Define MT19937 constants (32-bit RNG) +enum { + // Assumes W = 32 (omitting this) + N = 624, + M = 397, + R = 31, + A = 0x9908B0DF, + + F = 1812433253, + + U = 11, + // Assumes D = 0xFFFFFFFF (omitting this) + + S = 7, + B = 0x9D2C5680, + + T = 15, + C = 0xEFC60000, + + L = 18, + + MASK_LOWER = (1ull << R) - 1, + MASK_UPPER = (1ull << R) +}; + +struct mt_state { + uint32_t mt[N]; + off_t start; +}; + + +static uint32_t mt[N]; +static uint16_t index; + +// Re-init with a given seed +void Initialize(const uint32_t seed) { + uint32_t i; + + mt[0] = seed; + + for(i=1; i> 30)) + i); + } + + index = N; +} + +static void Twist() { + uint32_t i, x, xA; + + for(i=0; i> 1; + + if(x & 0x1) + xA ^= A; + + mt[i] = mt[(i+M) % N] ^ xA; + } + + index = 0; +} + +// Obtain a 32-bit random number +uint32_t ExtractU32() { + uint32_t y; + int i = index; + + if ( index >= N ) + { + Twist(); + i = index; + } + + y = mt[i]; + index = i + 1; + + y ^= (y >> U); + y ^= (y << S) & B; + y ^= (y << T) & C; + y ^= (y >> L); + + return y; +} diff --git a/zeroes.c b/zeroes.c new file mode 100644 index 0000000..4fb196c --- /dev/null +++ b/zeroes.c @@ -0,0 +1,54 @@ +/* + * zeroes.c -- component to provide zeroes on demand. + */ + +#include +#include +#include + +#include "noisebox.h" + +// 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); +// } + +static int do_getattr(const char *path, struct stat *st) { +} + + +static int get_noise(size_t n, off_t offset, char* buf, + struct fuse_file_info *fi) { + printf("getting zeroes: %i:%i\n", n, offset); + char *tmp = calloc(n, sizeof(char)); + memcpy(buf, tmp, n); + free(tmp); + printf("zeroes obtained\n"); + return n; +} + +Noiser* zero_init(void) { + Noiser* n = malloc(sizeof(Noiser)); + n->name = "zero"; + n->state = NULL; + n->get_noise = get_noise; + + // manually keep track of file count for now. + n->noisefile_count = 3; + n->files = malloc(sizeof(NoiseFile *) * n->noisefile_count); + + n->files[0] = malloc(sizeof(NoiseFile)); + n->files[0]->name = "1M"; + n->files[0]->size = 1ULL<<20; + + n->files[1] = malloc(sizeof(NoiseFile)); + n->files[1]->name = "1G"; + n->files[1]->size = 1ULL<<30; + + n->files[2] = malloc(sizeof(NoiseFile)); + n->files[2]->name = "100G"; + n->files[2]->size = 100 * (1ULL<<30); + + return n; +}