first cut at fuse filesystem; files > 4K do not work yet; nor do deletion, and other things.
This commit is contained in:
parent
c7c729acfa
commit
00f5037f79
2 changed files with 437 additions and 0 deletions
3
src/apps/fuse/CMakeLists.txt
Normal file
3
src/apps/fuse/CMakeLists.txt
Normal 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
434
src/apps/fuse/stasis_fuse.c
Normal 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;
|
||||||
|
}
|
Loading…
Reference in a new issue