initial commit -- works, but needs features.
This commit is contained in:
commit
b5a5a3a931
|
|
@ -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
|
||||
|
|
@ -0,0 +1 @@
|
|||
noisebox -- a FUSE filesystem that contains predictable PRNG output.
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
Loading…
Reference in New Issue