#include <u.h>
#include <libc.h>
#include <fcall.h>
#include <thread.h>
#include <9p.h>
#include "dat.h"
#include "fns.h"
#define thdr r->ifcall
#define rhdr r->ofcall
extern int errno;
static void
response(Req *r)
{
char *err;
if (errno) {
err = xerrstr(errno);
chat("%s\n", err);
respond(r, err);
} else {
chat("OK\n");
respond(r, nil);
}
}
static void
rattach(Req *r)
{
Xfs *xf;
Xfile *root;
chat("attach(fid=%d,uname=\"%s\",aname=\"%s\",afid=\"%d\")...",
thdr.fid, thdr.uname, thdr.aname, thdr.afid);
errno = 0;
root = xfile(r->fid, Clean);
if(!root){
errno = Enomem;
goto error;
}
root->xf = xf = getxfs(thdr.aname);
if(!xf)
goto error;
/* now attach root inode */
if( get_inode(root, EXT2_ROOT_INODE) < 0 )
goto error;
r->fid->qid.type = QTDIR;
r->fid->qid.vers = 0;
root->xf->rootqid = r->fid->qid;
root->pinbr = EXT2_ROOT_INODE;
root->root = 1;
rhdr.qid = r->fid->qid;
error:
response(r);
}
static char *
rclone(Fid *fid, Fid *newfid)
{
Xfile *of = xfile(fid, Asis);
Xfile *nf = xfile(newfid, Clean);
chat("clone(fid=%d,newfid=%d)...", fid->fid, newfid->fid);
errno = 0;
if(!of)
errno = Eio;
else if(!nf)
errno = Enomem;
else{
Xfile *next = nf->next;
*nf = *of;
nf->next = next;
nf->fid = newfid->fid;
nf->root = 0;
}
chat("%s\n", errno? xerrstr(errno) : "OK");
return errno ? xerrstr(errno) : 0;
}
static char *
rwalk1(Fid *fid, char *name, Qid *qid)
{
Xfile *f=xfile(fid, Asis);
int nr, sinbr = 0;
chat("walk1(fid=%d,name=\"%s\")...", fid->fid, name);
errno = 0;
if( !f ){
chat("no xfile...");
goto error;
}
if( !(fid->qid.type & QTDIR) ){
chat("qid.type=0x%x...", fid->qid.type);
goto error;
}
sinbr = f->pinbr;
if( name == 0 || name[0] == 0 || !strcmp(name, ".") ){
*qid = fid->qid;
goto ok;
}else if( !strcmp(name, "..") ){
if( fid->qid.path == f->xf->rootqid.path ){
chat("walkup from root...");
*qid = fid->qid;
goto ok;
}
if( get_inode(f, f->pinbr) < 0 )
goto error;
if( f->pinbr == EXT2_ROOT_INODE ){
*qid = f->xf->rootqid;
f->pinbr = EXT2_ROOT_INODE;
} else {
*qid = (Qid){f->pinbr,0,QTDIR};
f->inbr = f->pinbr;
if( (nr = get_file(f, "..")) < 0 )
goto error;
f->pinbr = nr;
}
}else{
f->pinbr = f->inbr;
if( (nr = get_file(f, name)) < 0 )
goto error;
if( get_inode(f, nr) < 0 )
goto error;
*qid = (Qid){nr,0,0};
if( nr == EXT2_ROOT_INODE )
*qid = f->xf->rootqid;
else if( S_ISDIR(getmode(f)) )
qid->type = QTDIR;
/*strcpy(f->name, thdr.name);*/
}
ok:
chat("OK\n");
return 0;
error:
f->pinbr = sinbr;
chat("%s\n", xerrstr(Enonexist));
return xerrstr(Enonexist);
}
static void
rstat(Req *r)
{
Xfile *f=xfile(r->fid, Asis);
chat("stat(fid=%d)...", thdr.fid);
errno = 0;
if( !f )
errno = Eio;
else{
dostat(r->fid->qid, f, &r->d);
}
response(r);
}
static void
rwstat(Req *r)
{
Xfile *f=xfile(r->fid, Asis);
chat("wstat(fid=%d)...", thdr.fid);
errno = 0;
if( !f )
errno = Eio;
else
dowstat(f, &r->d);
response(r);
}
static void
rread(Req *r)
{
Xfile *f;
int nr;
chat("read(fid=%d,offset=%lld,count=%d)...",
thdr.fid, thdr.offset, thdr.count);
errno = 0;
if ( !(f=xfile(r->fid, Asis)) )
goto error;
if( r->fid->qid.type & QTDIR ){
nr = readdir(f, r->rbuf, thdr.offset, thdr.count);
}else
nr = readfile(f, r->rbuf, thdr.offset, thdr.count);
if(nr >= 0){
rhdr.count = nr;
chat("rcnt=%d...OK\n", nr);
respond(r, nil);
return;
}
error:
errno = Eio;
response(r);
}
static void
rwrite(Req *r)
{
Xfile *f; int nr;
chat("write(fid=%d,offset=%lld,count=%d)...",
thdr.fid, thdr.offset, thdr.count);
errno = 0;
if (!(f=xfile(r->fid, Asis)) ){
errno = Eio;
goto error;
}
if( !S_ISREG(getmode(f)) ){
errno = Elink;
goto error;
}
nr = writefile(f, thdr.data, thdr.offset, thdr.count);
if(nr >= 0){
rhdr.count = nr;
chat("rcnt=%d...OK\n", nr);
respond(r, nil);
return;
}
errno = Eio;
error:
response(r);
}
static void
destroyfid(Fid *fid)
{
chat("destroy(fid=%d)\n", fid->fid);
xfile(fid, Clunk);
/*syncbuf(xf);*/
}
static void
ropen(Req *r)
{
Xfile *f;
chat("open(fid=%d,mode=%d)...", thdr.fid, thdr.mode);
errno = 0;
f = xfile(r->fid, Asis);
if( !f ){
errno = Eio;
goto error;
}
if(thdr.mode & OTRUNC){
if( !S_ISREG(getmode(f)) ){
errno = Eperm;
goto error;
}
if(truncfile(f) < 0){
goto error;
}
}
chat("f->qid=0x%8.8lux...", r->fid->qid.path);
rhdr.qid = r->fid->qid;
error:
response(r);
}
static void
rcreate(Req *r)
{
Xfile *f;
int inr, perm;
chat("create(fid=%d,name=\"%s\",perm=%uo,mode=%d)...",
thdr.fid, thdr.name, thdr.perm, thdr.mode);
errno = 0;
if(strcmp(thdr.name, ".") == 0 || strcmp(thdr.name, "..") == 0){
errno = Eperm;
goto error;
}
f = xfile(r->fid, Asis);
if( !f ){
errno = Eio;
goto error;
}
if( strlen(thdr.name) > EXT2_NAME_LEN ){
chat("name too long ...");
errno = Elongname;
goto error;
}
/* create */
errno = 0;
if( thdr.perm & DMDIR ){
perm = (thdr.perm & ~0777) |
(getmode(f) & thdr.perm & 0777);
perm |= S_IFDIR;
inr = create_dir(f, thdr.name, perm);
}else{
perm = (thdr.perm & (~0777|0111)) |
(getmode(f) & thdr.perm & 0666);
perm |= S_IFREG;
inr = create_file(f, thdr.name, perm);
}
if( inr < 0 )
goto error;
/* fill with new inode */
f->pinbr = f->inbr;
if( get_inode(f, inr) < 0 ){
errno = Eio;
goto error;
}
r->fid->qid = (Qid){inr, 0, 0};
if( S_ISDIR(getmode(f)) )
r->fid->qid.type |= QTDIR;
chat("f->qid=0x%8.8lux...", r->fid->qid.path);
rhdr.qid = r->fid->qid;
error:
response(r);
}
static void
rremove(Req *r)
{
Xfile *f=xfile(r->fid, Asis);
chat("remove(fid=%d) ...", thdr.fid);
errno = 0;
if(!f){
errno = Eio;
goto error;
}
/* check permission here !!!!*/
unlink(f);
error:
response(r);
}
Srv ext2srv = {
.destroyfid = destroyfid,
.attach = rattach,
.stat = rstat,
.wstat = rwstat,
.clone = rclone,
.walk1 = rwalk1,
.open = ropen,
.read = rread,
.write = rwrite,
.create = rcreate,
.remove = rremove,
};
|