ref: 12351d11dff058fc674198e1242b029dc19fcd26
dir: /ext4srv.c/
#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; typedef struct Aux Aux; struct Aux { Part *p; char *path; union { ext4_file *file; ext4_dir *dir; }; int type; }; enum { Adir, Afile, }; static Opts opts = { .cachewb = 0, }; static void rattach(Req *r) { Aux *a; static char err[ERRMAX]; 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; } 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 *) { threadnotify(note, 1); } static void rend(Srv *) { closeallparts(); threadexitsall(nil); } static Srv fs = { .attach = rattach, .open = ropen, .create = rcreate, .read = rread, .write = rwrite, .remove = rremove, .stat = rstat, .wstat = rwstat, .walk1 = rwalk1, .clone = rclone, .destroyfid = rdestroyfid, .start = rstart, .end = rend, }; static void usage(void) { fprint(2, "usage: %s [-C] [-s srvname]\n", argv0); threadexitsall("usage"); } void threadmain(int argc, char **argv) { char *srv; srv = "ext4"; ARGBEGIN{ case 'D': chatty9p++; break; case 'C': opts.cachewb = 1; break; case 's': srv = EARGF(usage()); }ARGEND if(argc != 0) usage(); threadpostmountsrv(&fs, srv, nil, 0); threadexits(nil); }