ref: babf901b4a508c3ec5d1f89655f10377bbdf9637
dir: /tools/styxtest/styxtest.c/
#include <lib9.h>
#include "styxserver.h"
/*
* An in-memory file server
* allowing truncation, removal on closure, wstat and
* all other file operations
*/
char *fsremove(Qid);
Styxserver *server;
char*
fsopen(Qid *qid, int mode)
{
Styxfile *f;
f = styxfindfile(server, qid->path);
if(mode&OTRUNC){ /* truncate on open */
styxfree(f->u);
f->u = nil;
f->d.length = 0;
}
return nil;
}
char*
fsclose(Qid qid, int mode)
{
if(mode&ORCLOSE) /* remove on close */
return fsremove(qid);
return nil;
}
char *
fscreate(Qid *qid, char *name, int perm, int mode)
{
int isdir;
Styxfile *f;
USED(mode);
isdir = perm&DMDIR;
if(isdir)
f = styxadddir(server, qid->path, -1, name, perm, "inferno");
else
f = styxaddfile(server, qid->path, -1, name, perm, "inferno");
if(f == nil)
return Eexist;
f->u = nil;
f->d.length = 0;
*qid = f->d.qid;
return nil;
}
char *
fsremove(Qid qid)
{
Styxfile *f;
f = styxfindfile(server, qid.path);
if((f->d.qid.type&QTDIR) && f->child != nil)
return "directory not empty";
styxfree(f->u);
styxrmfile(server, qid.path);
return nil;
}
char *
fsread(Qid qid, char *buf, ulong *n, vlong off)
{
int m;
Styxfile *f;
f = styxfindfile(server, qid.path);
m = f->d.length;
if(off >= m)
*n = 0;
else{
if(off + *n > m)
*n = m-off;
memmove(buf, (char*)f->u+off, *n);
}
return nil;
}
char*
fswrite(Qid qid, char *buf, ulong *n, vlong off)
{
Styxfile *f;
vlong m, p;
char *u;
f = styxfindfile(server, qid.path);
m = f->d.length;
p = off + *n;
if(p > m){ /* just grab a larger piece of memory */
u = styxmalloc(p);
if(u == nil)
return "out of memory";
memset(u, 0, p);
memmove(u, f->u, m);
styxfree(f->u);
f->u = u;
f->d.length = p;
}
memmove((char*)f->u+off, buf, *n);
return nil;
}
char*
fswstat(Qid qid, Dir *d)
{
Styxfile *f, *tf;
Client *c;
int owner;
/* the most complicated operation when fully allowed */
c = styxclient(server);
f = styxfindfile(server, qid.path);
owner = strcmp(c->uname, f->d.uid) == 0;
if(d->name != nil && strcmp(d->name, f->d.name) != 0){
/* need write permission in parent directory */
if(!styxperm(f->parent, c->uname, OWRITE))
return Eperm;
if((tf = styxaddfile(server, f->parent->d.qid.path, -1, d->name, 0, "")) == nil){
/* file with same name exists */
return Eexist;
}
else{
/* undo above addfile */
styxrmfile(server, tf->d.qid.path);
}
/* ok to change name now */
styxfree(f->d.name);
f->d.name = strdup(d->name);
}
if(d->uid != nil && strcmp(d->uid, f->d.uid) != 0){
if(!owner)
return Eperm;
styxfree(f->d.uid);
f->d.uid = strdup(d->uid);
}
if(d->gid != nil && strcmp(d->gid, f->d.gid) != 0){
if(!owner)
return Eperm;
styxfree(f->d.gid);
f->d.gid = strdup(d->gid);
}
if(d->mode != ~0 && d->mode != f->d.mode){
if(!owner)
return Eperm;
if((d->mode&DMDIR) != (f->d.mode&DMDIR))
return Eperm; /* cannot change file->directory or vice-verse */
f->d.mode = d->mode;
}
if(d->mtime != ~0 && d->mtime != f->d.mtime){
if(!owner)
return Eperm;
f->d.mtime = d->mtime;
}
/* all other file attributes cannot be changed by wstat */
return nil;
}
Styxops ops = {
nil, /* newclient */
nil, /* freeclient */
nil, /* attach */
nil, /* walk */
fsopen, /* open */
fscreate, /* create */
fsread, /* read */
fswrite, /* write */
fsclose, /* close */
fsremove, /* remove */
nil, /* stat */
fswstat, /* wstat */
};
void
main(int argc, char **argv)
{
Styxserver s;
USED(argc);
USED(argv);
server = &s;
styxdebug();
styxinit(&s, &ops, "6701", 0777, 1);
for(;;){
styxwait(&s);
styxprocess(&s);
}
exits(nil);
}