initial commit -- works, but needs features.

This commit is contained in:
chris t 2020-09-13 08:45:36 -07:00
commit b5a5a3a931
7 changed files with 627 additions and 0 deletions

17
Makefile Normal file
View File

@ -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

1
README Normal file
View File

@ -0,0 +1 @@
noisebox -- a FUSE filesystem that contains predictable PRNG output.

266
fuse.c Normal file
View File

@ -0,0 +1,266 @@
#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);
}

161
mersenne.c Normal file
View File

@ -0,0 +1,161 @@
/*
* mersenne.c -- component to provide random numbers on demand.
*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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<N; i++) {
x = (mt[i] & MASK_UPPER) + (mt[(i+1) % N] & MASK_LOWER);
xA = x >> 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<N; i++) {
mt[i] = (F * (mt[i-1] ^ (mt[i-1] >> 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; i<count; i++) {
tmp[i] = extract_u32(state);
}
// consumed is always in uint32_t.
printf("advancing consumed: %i + %i\n", state->consumed, 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;
}

33
noisebox.h Normal file
View File

@ -0,0 +1,33 @@
/*
* noisebox.h -- interfaces for noise provision.
*/
#include <fuse.h>
#include <stddef.h>
#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

95
random.c Normal file
View File

@ -0,0 +1,95 @@
/*
* random.c -- prng whatnot.
*
* mersenne twister implementation from wikipedia, via
* https://github.com/bmurray7/mersenne-twister-examples/
*/
#include <stdint.h>
#include <stdlib.h>
// 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<N; i++) {
mt[i] = (F * (mt[i-1] ^ (mt[i-1] >> 30)) + i);
}
index = N;
}
static void Twist() {
uint32_t i, x, xA;
for(i=0; i<N; i++) {
x = (mt[i] & MASK_UPPER) + (mt[(i+1) % N] & MASK_LOWER);
xA = x >> 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;
}

54
zeroes.c Normal file
View File

@ -0,0 +1,54 @@
/*
* zeroes.c -- component to provide zeroes on demand.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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;
}