ref: 12351d11dff058fc674198e1242b029dc19fcd26
parent: 7c4ed936d9990c8fd790e655585a0ff4028b6ba8
author: Sigrid Solveig Haflínudóttir <ftrvxmtrx@gmail.com>
date: Sat Nov 7 06:56:09 EST 2020
read-only mode works now; still no group mapping or permission checking
--- a/README.md
+++ b/README.md
@@ -1,3 +1,10 @@
# ext4srv
Ext[2-4] file system for Plan 9. *WIP*
+
+## Usage
+
+ ; mk install
+ ; ext4srv
+ ; mount /dev/ext4 /n/linux /n/sdN0/ext4partition
+ ; ls -l /n/linux
--- a/common.h
+++ b/common.h
@@ -1,33 +1,34 @@
#pragma lib "../lwext4/src/liblwext4.a"
-typedef struct Group Group;
-typedef struct Groups Groups;
typedef struct Opts Opts;
typedef struct Part Part;
-#pragma incomplete Part
+
#pragma varargck type "Ð" Part*
#pragma varargck type "M" Part*
-struct Group {
- u32int id;
- char *name;
- char **memb;
- int nmemb;
+struct Opts {
+ int cachewb;
};
-struct Groups {
- char *raw;
- Group *g;
- int ng;
-};
+struct Part {
+ Ref;
+ QLock;
+ Part *prev, *next;
-struct Opts {
- int cachewb;
+ char dev[32];
+ char mnt[32];
+
+ struct ext4_blockdev bdev;
+ struct ext4_blockdev_iface bdif;
+ Qid qid;
+ Qid qidmask;
+ Groups groups;
+ int f;
+ uchar blkbuf[];
};
Part *openpart(char *dev, Opts *opts);
void closepart(Part *p);
+void closeallparts(void);
char *errno2s(int err);
-int loadgroups(Groups *gs, char *raw);
-void freegroups(Groups *gs);
--- a/ext4srv.c
+++ b/ext4srv.c
@@ -1,7 +1,9 @@
#include <ext4.h>
+#include <ext4_inode.h>
#include <fcall.h>
#include <thread.h>
#include <9p.h>
+#include "group.h"
#include "common.h"
int mainstacksize = 65536;
@@ -9,7 +11,8 @@
typedef struct Aux Aux;
struct Aux {
- Part *part;
+ Part *p;
+ char *path;
union {
ext4_file *file;
ext4_dir *dir;
@@ -18,65 +21,346 @@
};
enum {
- Apart,
- Afile,
Adir,
+ Afile,
};
+static Opts opts = {
+ .cachewb = 0,
+};
+
static void
rattach(Req *r)
{
-}
+ Aux *a;
+ static char err[ERRMAX];
-static void
-rauth(Req *r)
-{
+ if((a = calloc(1, sizeof(*a))) == nil)
+ respond(r, "memory");
+ else if((a->p = openpart(r->ifcall.aname, &opts)) == nil){
+ free(a);
+ rerrstr(err, sizeof(err));
+ respond(r, err);
+ }else{
+ incref(a->p);
+ a->type = Adir;
+ a->path = strdup("");
+ r->ofcall.qid = a->p->qidmask;
+ r->fid->qid = a->p->qidmask;
+ r->fid->aux = a;
+ respond(r, nil);
+ }
}
static void
ropen(Req *r)
{
+ Aux *a;
+ char *path;
+ int res;
+
+ a = r->fid->aux;
+ switch(a->type){
+ case Adir:
+ if(r->ifcall.mode != OREAD){
+ respond(r, "permission denied");
+ return;
+ }
+ if(a->dir != nil){
+ respond(r, "double open");
+ return;
+ }
+ if((a->dir = malloc(sizeof(*a->dir))) == nil)
+ goto Nomem;
+ if((path = smprint("%M/%s", a->p, a->path)) == nil){
+ free(a->dir);
+ a->dir = nil;
+ goto Nomem;
+ }
+ res = ext4_dir_open(a->dir, path);
+ free(path);
+ if(res != 0){
+ free(a->dir);
+ a->dir = nil;
+ respond(r, errno2s(res));
+ return;
+ }
+ break;
+
+ case Afile:
+ if(r->ifcall.mode != OREAD){
+ respond(r, "permission denied");
+ return;
+ }
+ if(a->file != nil){
+ respond(r, "double open");
+ return;
+ }
+ if((a->file = malloc(sizeof(*a->file))) == nil)
+ goto Nomem;
+ if((path = smprint("%M/%s", a->p, a->path)) == nil){
+ free(a->file);
+ a->file = nil;
+ goto Nomem;
+ }
+ res = ext4_fopen2(a->file, path, O_RDONLY);
+ free(path);
+ if(res != 0){
+ free(a->file);
+ a->file = nil;
+ respond(r, errno2s(res));
+ return;
+ }
+ break;
+
+Nomem:
+ respond(r, "memory");
+ return;
+ }
+
+ respond(r, nil);
}
static void
rcreate(Req *r)
{
+ respond(r, "nope");
}
+static char *
+linkresolve(Aux *a, char *s)
+{
+ char *q;
+ char buf[4096+1];
+ ulong sz;
+
+ if(ext4_readlink(s, buf, sizeof(buf)-1, &sz) == 0){
+ buf[sz] = 0;
+ cleanname(buf);
+ if(buf[0] == '/'){
+ free(s);
+ s = smprint("%M%s", a->p, buf);
+ }else{
+ q = strrchr(s, '/');
+ *q = 0;
+ q = s;
+ s = smprint("%s/%s", q, buf);
+ cleanname(s);
+ free(q);
+ }
+ }
+
+ return s;
+}
+
+static int
+dirfill(Dir *dir, Aux *a, char *path)
+{
+ struct ext4_inode inode;
+ Group *g;
+ char *s, *q;
+ int r, i;
+ u32int uid, gid, t, ino;
+ struct ext4_sblock *sb;
+
+ memset(dir, 0, sizeof(*dir));
+ s = smprint("%M/", a->p);
+ r = ext4_get_sblock(s, &sb);
+ free(s);
+ if(r != 0){
+ fprint(2, "sblock: %s\n", errno2s(r));
+ return -1;
+ }
+
+ if(path == nil){
+ path = a->path;
+ s = smprint("%M/%s", a->p, a->path);
+ }else{
+ if(*a->path == 0 && *path == 0)
+ path = "/";
+ s = smprint("%M%s%s/%s", a->p, *a->path ? "/" : "", a->path, path);
+ }
+ s = linkresolve(a, s);
+ if((r = ext4_raw_inode_fill(s, &ino, &inode)) != 0)
+ fprint(2, "inode: %s: %s\n", s, errno2s(r));
+
+ dir->mode = ext4_inode_get_mode(sb, &inode);
+ dir->qid.path = a->p->qid.path | ino;
+ dir->qid.vers = ext4_inode_get_generation(&inode);
+ t = ext4_inode_type(sb, &inode);
+ if(t & EXT4_INODE_MODE_DIRECTORY){
+ dir->qid.type |= QTDIR;
+ dir->mode |= DMDIR;
+ }else
+ dir->length = ext4_inode_get_size(sb, &inode);
+ if(ext4_inode_get_flags(&inode) & EXT4_INODE_FLAG_APPEND){
+ dir->qid.type |= QTAPPEND;
+ dir->mode |= DMAPPEND;
+ }
+
+ if((q = strrchr(path, '/')) != nil)
+ path = q+1;
+ dir->name = estrdup9p(path);
+ dir->atime = ext4_inode_get_access_time(&inode);
+ dir->mtime = ext4_inode_get_modif_time(&inode);
+
+ uid = ext4_inode_get_uid(&inode);
+ gid = ext4_inode_get_gid(&inode);
+ for(i = 0, g = a->p->groups.g; i < a->p->groups.ng && (dir->uid == nil || dir->gid == nil); i++, g++){
+ if(g->id == uid)
+ dir->uid = estrdup9p(g->name);
+ if(g->id == gid)
+ dir->gid = estrdup9p(g->name);
+ }
+
+ free(s);
+
+ return 0;
+}
+
+static int
+dirgen(int n, Dir *dir, void *aux)
+{
+ const ext4_direntry *e;
+ Aux *a;
+
+ a = aux;
+ if(n == 0)
+ ext4_dir_entry_rewind(a->dir);
+ do{
+ if((e = ext4_dir_entry_next(a->dir)) == nil)
+ return -1;
+ }while(strcmp((char*)e->name, ".") == 0 || strcmp((char*)e->name, "..") == 0);
+
+ return dirfill(dir, a, (char*)e->name);
+}
+
static void
rread(Req *r)
{
+ Aux *a;
+ ulong n;
+
+ a = r->fid->aux;
+ if(a->type == Adir && a->dir != nil){
+ dirread9p(r, dirgen, a);
+ respond(r, nil);
+ return;
+ }else if(a->type == Afile && a->file != nil){
+ ext4_fseek(a->file, r->ifcall.offset, 0);
+ if(ext4_fread(a->file, r->ofcall.data, r->ifcall.count, &n) != 0){
+ respond(r, "i/o error");
+ }else{
+ r->ofcall.count = n;
+ respond(r, nil);
+ }
+ return;
+ }
+
+ respond(r, "eh?");
}
static void
rwrite(Req *r)
{
+ respond(r, "nope");
}
static void
rremove(Req *r)
{
+ respond(r, "nope");
}
static void
rstat(Req *r)
{
+ Aux *a;
+
+ a = r->fid->aux;
+ dirfill(&r->d, a, nil);
+
+ respond(r, nil);
}
static void
rwstat(Req *r)
{
+ respond(r, "nope");
}
static char *
rwalk1(Fid *fid, char *name, Qid *qid)
{
+ Aux *a;
+ char *s, *q;
+ u32int ino, t;
+ struct ext4_inode inode;
+ int r;
+ struct ext4_sblock *sb;
+
+ a = fid->aux;
+
+ s = smprint("%M/", a->p);
+ if((r = ext4_get_sblock(s, &sb)) != 0)
+ goto error;
+ free(s);
+
+ s = smprint("%M/%s", a->p, a->path);
+ s = linkresolve(a, s);
+
+ q = s;
+ s = smprint("%s/%s", q, name);
+ cleanname(s);
+ free(q);
+ s = linkresolve(a, s);
+ if((r = ext4_raw_inode_fill(s, &ino, &inode)) != 0)
+ goto error;
+ qid->type = 0;
+ qid->path = a->p->qid.path | ino;
+ qid->vers = ext4_inode_get_generation(&inode);
+ t = ext4_inode_type(sb, &inode);
+ if(t & EXT4_INODE_MODE_DIRECTORY){
+ qid->type |= QTDIR;
+ a->type = Adir;
+ }else
+ a->type = Afile;
+ if(ext4_inode_get_flags(&inode) & EXT4_INODE_FLAG_APPEND)
+ qid->type |= QTAPPEND;
+ free(a->path);
+ a->path = strdup(strchr(s+1, '/')+1);
+ free(s);
+ fid->qid = *qid;
+
return nil;
+error:
+ free(s);
+ return errno2s(r);
}
static char *
rclone(Fid *oldfid, Fid *newfid)
{
+ Aux *a, *c;
+
+ a = oldfid->aux;
+ switch(a->type){
+ case Afile:
+ case Adir:
+ if((c = calloc(1, sizeof(*c))) == nil)
+ return "memory";
+ memmove(c, a, sizeof(*c));
+ c->path = strdup(a->path);
+ c->file = nil;
+ c->dir = nil;
+ break;
+
+ default:
+ return "unknown aux type";
+ }
+ incref(c->p);
+ newfid->aux = c;
+
return nil;
}
@@ -83,16 +367,56 @@
static void
rdestroyfid(Fid *fid)
{
+ Aux *a;
+
+ a = fid->aux;
+ if(a == nil)
+ return;
+ fid->aux = nil;
+
+ if(a->type == Adir){
+ if(a->dir != nil){
+ ext4_dir_close(a->dir);
+ free(a->dir);
+ }
+ }else if(a->type == Afile){
+ if(a->file != nil){
+ ext4_fclose(a->file);
+ free(a->file);
+ }
+ }else{
+ /* that would be a BUG */
+ return;
+ }
+
+ if(decref(a->p) == 0)
+ closepart(a->p);
+ free(a->path);
+ free(a);
}
+static int
+note(void *, char *s)
+{
+ if(strncmp(s, "sys:", 4) != 0){
+ closeallparts();
+ return 1;
+ }
+
+ return 0;
+}
+
static void
-rstart(Srv *s)
+rstart(Srv *)
{
+ threadnotify(note, 1);
}
static void
-rend(Srv *s)
+rend(Srv *)
{
+ closeallparts();
+ threadexitsall(nil);
}
static Srv fs = {
@@ -111,23 +435,33 @@
.end = rend,
};
+static void
+usage(void)
+{
+ fprint(2, "usage: %s [-C] [-s srvname]\n", argv0);
+ threadexitsall("usage");
+}
+
void
threadmain(int argc, char **argv)
{
- Part *p;
- Opts opts = {
- .cachewb = 0,
- };
+ char *srv;
+ srv = "ext4";
ARGBEGIN{
+ case 'D':
+ chatty9p++;
+ break;
case 'C':
opts.cachewb = 1;
break;
+ case 's':
+ srv = EARGF(usage());
}ARGEND
- if((p = openpart(argv[0], &opts)) == nil)
- sysfatal("%r");
- closepart(p);
+ if(argc != 0)
+ usage();
- threadexitsall(nil);
+ threadpostmountsrv(&fs, srv, nil, 0);
+ threadexits(nil);
}
--- a/group.c
+++ b/group.c
@@ -1,6 +1,6 @@
#include <u.h>
#include <libc.h>
-#include "common.h"
+#include "group.h"
int
loadgroups(Groups *gs, char *raw)
--- /dev/null
+++ b/group.h
@@ -1,0 +1,18 @@
+typedef struct Group Group;
+typedef struct Groups Groups;
+
+struct Group {
+ u32int id;
+ char *name;
+ char **memb;
+ int nmemb;
+};
+
+struct Groups {
+ char *raw;
+ Group *g;
+ int ng;
+};
+
+int loadgroups(Groups *gs, char *raw);
+void freegroups(Groups *gs);
--- a/part.c
+++ b/part.c
@@ -1,31 +1,16 @@
#include <ext4.h>
-#include <fcall.h>
#include <thread.h>
-#include <9p.h>
+#include "group.h"
#include "common.h"
#define TRACE(fmt, ...) //fprint(2, fmt, __VA_ARGS__)
-struct Part {
- QLock;
- Part *prev, *next;
- int refcnt;
-
- char dev[32];
- char mnt[32];
-
- struct ext4_blockdev bdev;
- struct ext4_blockdev_iface bdif;
- Qid qid;
- Groups groups;
- int f;
- uchar blkbuf[];
-};
#define BDEV2PART(bdev) ((bdev)->bdif->p_user)
static struct {
QLock;
Part *ps;
+ u32int id;
}sv;
static long
@@ -329,9 +314,10 @@
if(sv.ps != nil)
sv.ps->prev = p;
sv.ps = p;
+ p->qidmask.path = ((uvlong)sv.id++) << 32;
+ p->qidmask.type = QTDIR;
}else{
close(f);
- p->refcnt++;
}
free(d);
@@ -341,7 +327,9 @@
return p;
error:
- close(f);
+ werrstr("openpart: %r");
+ if(f >= 0)
+ close(f);
free(d);
free(p);
free(s);
@@ -356,23 +344,28 @@
int r;
qlock(&sv);
- if(--p->refcnt < 0){
- ext4_cache_write_back(p->mnt, 0);
- if((r = ext4_journal_stop(p->mnt)) != 0 && r != ENOTSUP)
- fprint(2, "closepart: journal %s: %s\n", p->mnt, errno2s(r));
- if((r = ext4_umount(p->mnt)) != 0 && r != ENOTSUP)
- fprint(2, "closepart: umount %s: %s\n", p->mnt, errno2s(r));
- if((r = ext4_device_unregister(p->dev)) != 0 && r != ENOTSUP)
- fprint(2, "closepart: unregister %s: %s\n", p->dev, errno2s(r));
- close(p->f);
- if(p->prev != nil)
- p->prev = p->next;
- if(p->next != nil)
- p->next->prev = p->prev;
- if(p == sv.ps)
- sv.ps = p->next;
- freegroups(&p->groups);
- free(p);
- }
+ ext4_cache_write_back(p->mnt, 0);
+ if((r = ext4_journal_stop(p->mnt)) != 0 && r != ENOTSUP)
+ fprint(2, "closepart: journal %s: %s\n", p->mnt, errno2s(r));
+ if((r = ext4_umount(p->mnt)) != 0 && r != ENOTSUP)
+ fprint(2, "closepart: umount %s: %s\n", p->mnt, errno2s(r));
+ if((r = ext4_device_unregister(p->dev)) != 0 && r != ENOTSUP)
+ fprint(2, "closepart: unregister %s: %s\n", p->dev, errno2s(r));
+ close(p->f);
+ if(p->prev != nil)
+ p->prev = p->next;
+ if(p->next != nil)
+ p->next->prev = p->prev;
+ if(p == sv.ps)
+ sv.ps = p->next;
+ freegroups(&p->groups);
+ free(p);
qunlock(&sv);
+}
+
+void
+closeallparts(void)
+{
+ while(sv.ps != nil)
+ closepart(sv.ps);
}