first cut at fuse filesystem; files > 4K do not work yet; nor do deletion, and other things.

This commit is contained in:
Sears Russell 2008-11-05 22:18:11 +00:00
parent c7c729acfa
commit 00f5037f79
2 changed files with 437 additions and 0 deletions

View file

@ -0,0 +1,3 @@
ADD_EXECUTABLE(stasis_fuse stasis_fuse.c)
SET_TARGET_PROPERTIES(stasis_fuse PROPERTIES COMPILE_FLAGS -D_FILE_OFFSET_BITS=64)
TARGET_LINK_LIBRARIES(stasis_fuse ${COMMON_LIBRARIES} -lfuse)

434
src/apps/fuse/stasis_fuse.c Normal file
View file

@ -0,0 +1,434 @@
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2005 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU GPL.
See the file COPYING.
*/
#include <stasis/transactional.h>
#define FUSE_USE_VERSION 26
#include <fuse/fuse.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <libgen.h> // for basename, dirname.
#include <fcntl.h>
typedef struct {
struct stat s; // what type is this entry?
} stasis_dir_entry;
static int stasis_lookup_helper(const char *path, stasis_dir_entry** subentry) {
return ThashLookup(-1, ROOT_RECORD, (byte*)path, strlen(path)+1, (byte**)subentry);
}
static int stasis_getattr(const char *path, struct stat *stbuf)
{
int res = 0;
memset(stbuf, 0, sizeof(struct stat));
/* if(strcmp(path, "/") == 0) {
stbuf->st_mode = S_IFDIR | 0755;
stbuf->st_nlink = 2;
} else { */
/* memset(stbuf, 0, sizeof(struct stat));
else if(strcmp(path, hello_path) == 0) {
stbuf->st_mode = S_IFREG | 0444;
stbuf->st_nlink = 1;
stbuf->st_size = strlen(hello_str);
}
else {
res = -ENOENT;
} */
stasis_dir_entry * e;
int sz = stasis_lookup_helper(path, &e);
if(sz == -1) {
res = -ENOENT;
} else {
memcpy(stbuf, &(e->s), sizeof(*stbuf));
free(e);
}
return res;
}
static stasis_dir_entry* malloc_nod(int*sz) {
*sz = sizeof(stasis_dir_entry);
return calloc(1, sizeof(stasis_dir_entry));
}
static int stasis_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
off_t offset, struct fuse_file_info *fi)
{
(void) offset;
(void) fi;
stasis_dir_entry * entry;
printf("lu ->%s<- %d\n", path, (int)strlen(path)+1);fflush(stdout);
int entrylen = ThashLookup(-1, ROOT_RECORD, (byte*)path, strlen(path)+1,(byte**)&entry);
printf("readdir %s %d\n", path, entrylen); fflush(stdout);
int res;
if(entrylen == -1) {
res = -ENOENT;
} else {
if(entry->s.st_mode & S_IFDIR) { // dir
filler(buf, ".", &(entry->s), 0); // xxx offsets
filler(buf, "..", NULL, 0);
for(char* next = (char*)(entry+1);
next != ((char*)entry) + entrylen;
next += (strlen(next)+1)) {
assert(next < ((char*)entry)+entrylen);
printf("found entry %s\n", next); fflush(stdout);
char * subentrypath = malloc(strlen(next)+strlen(path)+1);
if(0==strcmp(path,"/")) {
subentrypath = malloc(strlen(next)+strlen(path)+1);
strcpy(subentrypath,path);
strcat(subentrypath,next);
} else {
subentrypath = malloc(strlen(next)+strlen(path)+2);
strcpy(subentrypath,path);
strcat(subentrypath,"/");
strcat(subentrypath,next);
}
stasis_dir_entry * subentry;
int subentry_len = stasis_lookup_helper(subentrypath,&subentry);
if(subentry_len == -1) { abort(); }
filler(buf, next, &(subentry->s), 0);
free(subentry);
}
} else {
res = -ENOTDIR;
}
}
free(entry);
return 0;
}
static int stasis_open(const char *path, struct fuse_file_info *fi)
{
/* if(strcmp(path, hello_path) != 0)
return -ENOENT;
if((fi->flags & 3) != O_RDONLY)
return -EACCES; */
int res = 0;
stasis_dir_entry * entry;
int entrylen = ThashLookup(-1, ROOT_RECORD,
(const byte*)path, strlen(path)+1,
(byte**)&entry);
if(entrylen != -1) {
// XXX check permissions?
if(entry->s.st_mode & S_IFDIR) {
printf("found a directory entry %s\n",path); fflush(stdout);
res = -EISDIR;
} else if(entry->s.st_mode & S_IFREG) {
printf("found and regular entry %s\n",path); fflush(stdout);
res = 0;
} else { // XXX do something else?
res = 0;
}
free(entry);
} else {
res = -ENOENT;
}
return res;
}
static int stasis_write(const char *path, const char *buf, const size_t sz, const off_t off,
struct fuse_file_info * fi) {
stasis_dir_entry *e;
int xid = Tbegin();
int res = 0;
int entsz = ThashLookup(xid, ROOT_RECORD, (const byte*)path, strlen(path)+1, (byte**)&e);
if(entsz == -1) {
res = -ENOENT;
} else {
assert(entsz > sizeof(stasis_dir_entry));
if(S_ISREG(e->s.st_mode)) {
assert(entsz == (sizeof(stasis_dir_entry)+sizeof(recordid)));
recordid * blob_rid = (recordid*)(e+1);
int updateRid = 0;
if(blob_rid->page == NULLRID.page &&
blob_rid->slot == NULLRID.slot) {
// alloc blob
updateRid = 1;
*blob_rid = Talloc(xid, sz+off);
char* realbuf;
if(off) {
realbuf = calloc(sz+off,sizeof(char));
memcpy(realbuf+off,buf,sz);
} else {
realbuf = (char*)buf;
}
Tset(xid, *blob_rid, realbuf);
if(off) {
free(realbuf);
}
} else {
// memcpy old blob into buffer, free old blob, alloc + write new blob, update hash
size_t oldlen = TrecordSize(xid, *blob_rid);
if(oldlen >= sz+off) {
byte * tmp = malloc(oldlen);
Tread(xid, *blob_rid, tmp);
memcpy(tmp+off,buf,sz);
Tset(xid, *blob_rid, tmp);
free(tmp);
} else {
byte * tmp = calloc(sz+off,sizeof(char));
Tread(xid, *blob_rid, tmp);
memcpy(tmp+off,buf,sz);
Tdealloc(xid, *blob_rid);
updateRid = 1;
*blob_rid = Talloc(xid, off+sz);
Tset(xid,*blob_rid,tmp);
free(tmp);
}
}
if(updateRid) {
e->s.st_size = off+sz;
ThashInsert(xid, ROOT_RECORD, (const byte*)path, strlen(path)+1, (byte*)e,
sizeof(stasis_dir_entry)+sizeof(recordid));
}
} else {
res = -ENOTSUP;
}
}
if(!res) {
res = sz;
Tcommit(xid);
} else {
Tabort(xid);
}
return res;
}
static int hello_read(const char *path, char *buf, size_t size, off_t offset,
struct fuse_file_info *fi)
{
int res = 0;
stasis_dir_entry *e;
int entsz = ThashLookup(-1, ROOT_RECORD, (const byte*)path, strlen(path)+1, (byte**)&e);
if(entsz == -1) {
res = -ENOENT;
} else {
assert(entsz > sizeof(stasis_dir_entry));
if(S_ISREG(e->s.st_mode)) {
assert(entsz == (sizeof(stasis_dir_entry)+sizeof(recordid)));
recordid * blob_rid = (recordid*)(e+1);
if(size+offset > e->s.st_size) {
if(offset > e->s.st_size) {
size = 0;
} else {
size = e->s.st_size-offset;
}
}
if(size) {
byte * tmp = malloc(e->s.st_size);
Tread(-1, *blob_rid, tmp);
memcpy(buf, tmp+offset, size);
free(tmp);
}
res = size;
} else {
res = -ENOTSUP;
}
}
return res;
/*if(strcmp(path, hello_path) != 0)
len = strlen(hello_str);
if (offset < len) {
if (offset + size > len)
size = len - offset;
memcpy(buf, hello_str + offset, size);
} else
size = 0;
return size; */
}
static int stasis_mknod_helper(int xid, const char * path,
stasis_dir_entry * dir, int sz, int parent) {
printf("mk ->%s<- %d\n", path, (int)strlen(path)+1);fflush(stdout);
ThashInsert(xid, ROOT_RECORD, (const byte*)path, strlen(path)+1, (byte*)dir, sz);
if(parent) {
char * parentbuf = strdup(path);
char * parent = dirname(parentbuf);
printf("attaching to parent %s\n", parent); fflush(stdout);
char * filebuf = strdup(path);
char * file = basename(filebuf);
stasis_dir_entry * entry;
printf("lu ->%s<- %d\n", parent, (int)strlen(parent)+1);fflush(stdout);
int entrylen = ThashLookup(xid, ROOT_RECORD,
(const byte*)parent, strlen(parent)+1,
(byte**)&entry);
printf("entrylen %d\n",entrylen); fflush(stdout);
if(entrylen == -1) {
return -ENOENT;
} else {
const char * next;
for(next = (const char*)(entry+1);
next != ((char*)entry) + entrylen;
next += (strlen(next)+1)) {
assert(next < ((char*)entry)+entrylen);
printf("next: %s\n", next); fflush(stdout);fflush(stdout);
if(0 == strcmp(next, path)) {
break;
}
}
printf("forloop done\n"); fflush(stdout);
if(next == ((char*)entry)+entrylen) {
printf("inserting %s\n", path); fflush(stdout);
int newentrylen = entrylen+strlen(file)+1;
entry = realloc(entry, newentrylen);
strcpy(((char*)entry)+entrylen,file);
printf("parent ->%s<- %d; newlen=%d\n", parent, (int)strlen(parent)+1,
newentrylen);fflush(stdout);
ThashInsert(xid, ROOT_RECORD, (const byte*)parent, strlen(parent)+1,
(const byte*)entry, newentrylen);
}
}
}
printf("returning 0\n"); fflush(stdout);
return 0;
}
static int stasis_mknod(const char *path, mode_t mode, dev_t dev) {
int res = 0;
int xid = Tbegin();
int sz;
stasis_dir_entry * dir = malloc_nod(&sz);
dir->s.st_nlink = 1;
dir->s.st_mode = mode & 0777;
assert(!(dir->s.st_mode & S_IFDIR));
if(S_ISREG(mode)) {
dir->s.st_mode |= S_IFREG;
// dir->s.st_uid = 0;
// dir->s.st_gid = 0;
// dir->s.st_blksize = 4096; //USABLE_SIZE_OF_PAGE;
// dir->s.st_blocks = 1;
sz += sizeof(recordid);
dir = realloc(dir, sz);
*(recordid*)(dir+1) = NULLRID;
} else if(S_ISCHR(mode)) {
//XXX
res = -ENOTSUP;
} else if(S_ISBLK(mode)) {
//XXX
res = -ENOTSUP;
} else if(S_ISFIFO(mode)) {
//XXX
res = -ENOTSUP;
} else if(S_ISSOCK(mode)) {
//XXX
res = -ENOTSUP;
} else {
printf("invalid dev parameter to mknod: %ld", (long)dev); fflush(stdout);
res = -EINVAL;
}
if(!res) {
res = stasis_mknod_helper(xid,path,dir,sz,1);
}
if(!res) {
Tcommit(xid);
} else {
Tabort(xid);
}
free(dir);
return res;
}
static int stasis_mkdir(const char *path, mode_t mode) {
int xid = Tbegin();
int sz;
stasis_dir_entry * dir = malloc_nod(&sz);
dir->s.st_mode = S_IFDIR | mode;
dir->s.st_nlink = 2;
// dir->s.st_uid = 0;
// dir->s.st_gid = 0;
// dir->s.st_blksize = 4096; //USABLE_SIZE_OF_PAGE;
// dir->s.st_blocks = 1;
int ret = stasis_mknod_helper(xid,path,dir,sz,1);
free(dir);
if(ret) {
Tabort(xid);
} else {
Tcommit(xid);
}
return ret;
}
static struct fuse_operations hello_oper = {
.getattr = stasis_getattr,
.readdir = stasis_readdir,
.mkdir = stasis_mkdir,
.mknod = stasis_mknod,
.open = stasis_open,
.read = hello_read,
.write = stasis_write,
};
int main(int argc, char *argv[])
{
int ret;
Tinit();
int xid = Tbegin();
if(TrecordType(xid, ROOT_RECORD) == INVALID_SLOT) {
recordid rootEntry = ThashCreate(xid, VARIABLE_LENGTH, VARIABLE_LENGTH);
assert(ROOT_RECORD.page == rootEntry.page);
assert(ROOT_RECORD.slot == rootEntry.slot);
int sz;
stasis_dir_entry * dir = malloc_nod(&sz);
dir->s.st_mode = S_IFDIR | 0755; // XXX mode?
dir->s.st_nlink = 2;
// dir->s.st_uid = 0;
// dir->s.st_gid = 0;
// dir->s.st_blksize = 4096; //USABLE_SIZE_OF_PAGE;
// dir->s.st_blocks = 1;
stasis_mknod_helper(xid, "/", dir, sz, 0);
}
Tcommit(xid);
ret = fuse_main(argc, argv, &hello_oper, 0);
// Tdeinit();
return ret;
}