2011-03-30 12:46:40 +00:00
|
|
|
#include <u.h>
|
|
|
|
#include <libc.h>
|
|
|
|
#include <auth.h>
|
|
|
|
#include <fcall.h>
|
|
|
|
#include <thread.h>
|
|
|
|
#include <9p.h>
|
|
|
|
|
|
|
|
typedef struct Part Part;
|
|
|
|
typedef struct Trip Trip;
|
|
|
|
typedef struct Dbl Dbl;
|
|
|
|
typedef struct Ind Ind;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* with 8192-byte blocks and 4-byte pointers,
|
|
|
|
* double-indirect gets us 34 GB.
|
|
|
|
* triple-indirect gets us 70,368 GB.
|
|
|
|
*/
|
|
|
|
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
LOGBLKSZ = 13,
|
|
|
|
BLKSZ = 1<<LOGBLKSZ, /* 8192 */
|
2015-11-24 10:02:04 +00:00
|
|
|
NPTR = BLKSZ/sizeof(void*),
|
2011-03-30 12:46:40 +00:00
|
|
|
};
|
|
|
|
static uchar zero[BLKSZ];
|
|
|
|
|
|
|
|
struct Trip
|
|
|
|
{
|
|
|
|
Dbl *dbl[NPTR];
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Dbl
|
|
|
|
{
|
|
|
|
Ind *ind[NPTR];
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Ind
|
|
|
|
{
|
|
|
|
uchar *blk[NPTR];
|
|
|
|
};
|
|
|
|
|
|
|
|
Trip trip;
|
|
|
|
|
|
|
|
struct Part
|
|
|
|
{
|
|
|
|
int inuse;
|
|
|
|
int vers;
|
|
|
|
ulong mode;
|
|
|
|
char *name;
|
|
|
|
vlong offset; /* in sectors */
|
|
|
|
vlong length; /* in sectors */
|
|
|
|
};
|
|
|
|
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
Qroot = 0,
|
|
|
|
Qdir,
|
|
|
|
Qctl,
|
|
|
|
Qpart,
|
|
|
|
};
|
|
|
|
|
|
|
|
Part tab[64];
|
|
|
|
int fd = -1;
|
|
|
|
char *sdname = "sdXX";
|
|
|
|
ulong ctlmode = 0666;
|
|
|
|
char *inquiry = "aux/disksim hard drive";
|
|
|
|
vlong nsect, sectsize, c, h, s;
|
|
|
|
ulong time0;
|
|
|
|
int rdonly;
|
|
|
|
|
|
|
|
char*
|
|
|
|
ctlstring(void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
Fmt fmt;
|
|
|
|
|
|
|
|
fmtstrinit(&fmt);
|
|
|
|
fmtprint(&fmt, "inquiry %s\n", inquiry);
|
|
|
|
fmtprint(&fmt, "geometry %lld %lld %lld %lld %lld\n", nsect, sectsize, c, h, s);
|
|
|
|
for(i=0; i<nelem(tab); i++)
|
|
|
|
if(tab[i].inuse)
|
|
|
|
fmtprint(&fmt, "part %s %lld %lld\n", tab[i].name, tab[i].offset, tab[i].length);
|
|
|
|
return fmtstrflush(&fmt);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
addpart(char *name, vlong start, vlong end)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if(start < 0 || start > end || end > nsect){
|
|
|
|
werrstr("bad partition boundaries");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
for(i=0; i<nelem(tab); i++)
|
|
|
|
if(tab[i].inuse == 0)
|
|
|
|
break;
|
|
|
|
if(i == nelem(tab)){
|
|
|
|
werrstr("no free partition slots");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
free(tab[i].name);
|
|
|
|
tab[i].inuse = 1;
|
|
|
|
tab[i].name = estrdup9p(name);
|
|
|
|
tab[i].offset = start;
|
|
|
|
tab[i].length = end - start;
|
|
|
|
tab[i].mode = ctlmode;
|
|
|
|
tab[i].vers++;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
delpart(char *s)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for(i=0; i<nelem(tab); i++)
|
|
|
|
if(tab[i].inuse && strcmp(tab[i].name, s) == 0)
|
|
|
|
break;
|
|
|
|
if(i==nelem(tab)){
|
|
|
|
werrstr("partition not found");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
tab[i].inuse = 0;
|
|
|
|
free(tab[i].name);
|
|
|
|
tab[i].name = 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ctlwrite(Req *r)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
Cmdbuf *cb;
|
|
|
|
vlong start, end;
|
|
|
|
|
|
|
|
r->ofcall.count = r->ifcall.count;
|
|
|
|
cb = parsecmd(r->ifcall.data, r->ifcall.count);
|
|
|
|
if(cb->nf < 1){
|
|
|
|
respond(r, "empty control message");
|
|
|
|
free(cb);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(strcmp(cb->f[0], "part") == 0){
|
|
|
|
if(cb->nf != 4){
|
|
|
|
respondcmderror(r, cb, "part takes 3 args");
|
|
|
|
free(cb);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
start = strtoll(cb->f[2], 0, 0);
|
|
|
|
end = strtoll(cb->f[3], 0, 0);
|
|
|
|
if(addpart(cb->f[1], start, end) < 0){
|
|
|
|
respondcmderror(r, cb, "%r");
|
|
|
|
free(cb);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(strcmp(cb->f[0], "delpart") == 0){
|
|
|
|
if(cb->nf != 2){
|
|
|
|
respondcmderror(r, cb, "delpart takes 1 arg");
|
|
|
|
free(cb);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if(delpart(cb->f[1]) < 0){
|
|
|
|
respondcmderror(r, cb, "%r");
|
|
|
|
free(cb);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(strcmp(cb->f[0], "inquiry") == 0){
|
|
|
|
if(cb->nf != 2){
|
|
|
|
respondcmderror(r, cb, "inquiry takes 1 arg");
|
|
|
|
free(cb);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
free(inquiry);
|
|
|
|
inquiry = estrdup9p(cb->f[1]);
|
|
|
|
}
|
|
|
|
else if(strcmp(cb->f[0], "geometry") == 0){
|
|
|
|
if(cb->nf != 6){
|
|
|
|
respondcmderror(r, cb, "geometry takes 5 args");
|
|
|
|
free(cb);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
nsect = strtoll(cb->f[1], 0, 0);
|
|
|
|
sectsize = strtoll(cb->f[2], 0, 0);
|
|
|
|
c = strtoll(cb->f[3], 0, 0);
|
|
|
|
h = strtoll(cb->f[4], 0, 0);
|
|
|
|
s = strtoll(cb->f[5], 0, 0);
|
|
|
|
if(tab[0].inuse && strcmp(tab[0].name, "data") == 0 && tab[0].vers == 0){
|
|
|
|
tab[0].offset = 0;
|
|
|
|
tab[0].length = nsect;
|
|
|
|
}
|
|
|
|
for(i=0; i<nelem(tab); i++){
|
|
|
|
if(tab[i].inuse && tab[i].offset+tab[i].length > nsect){
|
|
|
|
tab[i].inuse = 0;
|
|
|
|
free(tab[i].name);
|
|
|
|
tab[i].name = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
respondcmderror(r, cb, "unknown control message");
|
|
|
|
free(cb);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
free(cb);
|
|
|
|
respond(r, nil);
|
|
|
|
}
|
|
|
|
|
|
|
|
void*
|
|
|
|
allocblk(vlong addr)
|
|
|
|
{
|
|
|
|
uchar *op;
|
|
|
|
static uchar *p;
|
|
|
|
static ulong n;
|
|
|
|
|
|
|
|
if(n == 0){
|
|
|
|
p = malloc(4*1024*1024);
|
|
|
|
if(p == 0)
|
|
|
|
sysfatal("out of memory");
|
|
|
|
n = 4*1024*1024;
|
|
|
|
}
|
|
|
|
op = p;
|
|
|
|
p += BLKSZ;
|
|
|
|
n -= BLKSZ;
|
|
|
|
memset(op, 0, BLKSZ);
|
|
|
|
if(fd != -1 && addr != -1)
|
|
|
|
pread(fd, op, BLKSZ, addr);
|
|
|
|
return op;
|
|
|
|
}
|
|
|
|
|
|
|
|
uchar*
|
|
|
|
getblock(vlong addr, int alloc)
|
|
|
|
{
|
|
|
|
Dbl *p2;
|
|
|
|
Ind *p1;
|
|
|
|
uchar *p0;
|
|
|
|
uint i0, i1, i2;
|
|
|
|
vlong oaddr;
|
|
|
|
|
|
|
|
if(fd >= 0)
|
|
|
|
alloc = 1;
|
|
|
|
|
|
|
|
addr >>= LOGBLKSZ;
|
|
|
|
oaddr = addr<<LOGBLKSZ;
|
2015-11-24 10:02:04 +00:00
|
|
|
i0 = addr % NPTR;
|
|
|
|
addr /= NPTR;
|
|
|
|
i1 = addr % NPTR;
|
|
|
|
addr /= NPTR;
|
|
|
|
i2 = addr % NPTR;
|
|
|
|
addr /= NPTR;
|
2011-03-30 12:46:40 +00:00
|
|
|
assert(addr == 0);
|
|
|
|
|
|
|
|
if((p2 = trip.dbl[i2]) == 0){
|
|
|
|
if(!alloc)
|
|
|
|
return zero;
|
|
|
|
trip.dbl[i2] = p2 = allocblk(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if((p1 = p2->ind[i1]) == 0){
|
|
|
|
if(!alloc)
|
|
|
|
return zero;
|
|
|
|
p2->ind[i1] = p1 = allocblk(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if((p0 = p1->blk[i0]) == 0){
|
|
|
|
if(!alloc)
|
|
|
|
return zero;
|
|
|
|
p1->blk[i0] = p0 = allocblk(oaddr);
|
|
|
|
}
|
|
|
|
return p0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
dirty(vlong addr, uchar *buf)
|
|
|
|
{
|
|
|
|
vlong oaddr;
|
|
|
|
|
|
|
|
if(fd == -1 || rdonly)
|
|
|
|
return;
|
|
|
|
oaddr = addr&~((vlong)BLKSZ-1);
|
|
|
|
if(pwrite(fd, buf, BLKSZ, oaddr) != BLKSZ)
|
|
|
|
sysfatal("write: %r");
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
rootgen(int off, Dir *d, void*)
|
|
|
|
{
|
|
|
|
memset(d, 0, sizeof *d);
|
|
|
|
d->atime = time0;
|
|
|
|
d->mtime = time0;
|
|
|
|
if(off == 0){
|
|
|
|
d->name = estrdup9p(sdname);
|
|
|
|
d->mode = DMDIR|0777;
|
|
|
|
d->qid.path = Qdir;
|
|
|
|
d->qid.type = QTDIR;
|
|
|
|
d->uid = estrdup9p("disksim");
|
|
|
|
d->gid = estrdup9p("disksim");
|
|
|
|
d->muid = estrdup9p("");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
dirgen(int off, Dir *d, void*)
|
|
|
|
{
|
|
|
|
int n, j;
|
|
|
|
|
|
|
|
memset(d, 0, sizeof *d);
|
|
|
|
d->atime = time0;
|
|
|
|
d->mtime = time0;
|
|
|
|
if(off == 0){
|
|
|
|
d->name = estrdup9p("ctl");
|
|
|
|
d->mode = ctlmode;
|
|
|
|
d->qid.path = Qctl;
|
|
|
|
goto Have;
|
|
|
|
}
|
|
|
|
|
|
|
|
off--;
|
|
|
|
n = 0;
|
|
|
|
for(j=0; j<nelem(tab); j++){
|
|
|
|
if(tab[j].inuse==0)
|
|
|
|
continue;
|
|
|
|
if(n == off){
|
|
|
|
d->name = estrdup9p(tab[j].name);
|
|
|
|
d->length = tab[j].length*sectsize;
|
|
|
|
d->mode = tab[j].mode;
|
|
|
|
d->qid.path = Qpart+j;
|
|
|
|
d->qid.vers = tab[j].vers;
|
|
|
|
goto Have;
|
|
|
|
}
|
|
|
|
n++;
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
Have:
|
|
|
|
d->uid = estrdup9p("disksim");
|
|
|
|
d->gid = estrdup9p("disksim");
|
|
|
|
d->muid = estrdup9p("");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void*
|
2021-07-25 15:54:22 +00:00
|
|
|
evommem(void *a, void *b, usize n)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
|
|
|
return memmove(b, a, n);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2021-07-25 15:54:22 +00:00
|
|
|
isnonzero(void *v, usize n)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
|
|
|
uchar *a, *ea;
|
|
|
|
|
|
|
|
a = v;
|
|
|
|
ea = a+n;
|
|
|
|
for(; a<ea; a++)
|
|
|
|
if(*a)
|
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
rdwrpart(Req *r)
|
|
|
|
{
|
|
|
|
int q, nonzero;
|
|
|
|
Part *p;
|
|
|
|
vlong offset;
|
|
|
|
long count, tot, n, o;
|
|
|
|
uchar *blk, *dat;
|
2021-07-25 15:54:22 +00:00
|
|
|
void *(*move)(void*, void*, usize);
|
2011-03-30 12:46:40 +00:00
|
|
|
|
|
|
|
q = r->fid->qid.path-Qpart;
|
|
|
|
if(q < 0 || q > nelem(tab) || !tab[q].inuse || tab[q].vers != r->fid->qid.vers){
|
|
|
|
respond(r, "unknown partition");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
p = &tab[q];
|
|
|
|
offset = r->ifcall.offset;
|
|
|
|
count = r->ifcall.count;
|
|
|
|
if(offset < 0){
|
|
|
|
respond(r, "negative offset");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if(count < 0){
|
|
|
|
respond(r, "negative count");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if(offset > p->length*sectsize){
|
|
|
|
respond(r, "offset past end of partition");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if(offset+count > p->length*sectsize)
|
|
|
|
count = p->length*sectsize - offset;
|
|
|
|
offset += p->offset*sectsize;
|
|
|
|
|
|
|
|
if(r->ifcall.type == Tread)
|
|
|
|
move = memmove;
|
|
|
|
else
|
|
|
|
move = evommem;
|
|
|
|
|
|
|
|
tot = 0;
|
|
|
|
nonzero = 1;
|
|
|
|
if(r->ifcall.type == Tread)
|
|
|
|
dat = (uchar*)r->ofcall.data;
|
|
|
|
else{
|
|
|
|
dat = (uchar*)r->ifcall.data;
|
|
|
|
nonzero = isnonzero(dat, r->ifcall.count);
|
|
|
|
}
|
|
|
|
o = offset & (BLKSZ-1);
|
|
|
|
|
|
|
|
/* left fringe block */
|
|
|
|
if(o && count){
|
|
|
|
blk = getblock(offset, r->ifcall.type==Twrite && nonzero);
|
|
|
|
n = BLKSZ - o;
|
|
|
|
if(n > count)
|
|
|
|
n = count;
|
|
|
|
if(r->ifcall.type != Twrite || blk != zero)
|
|
|
|
(*move)(dat, blk+o, n);
|
|
|
|
if(r->ifcall.type == Twrite)
|
|
|
|
dirty(offset, blk);
|
|
|
|
tot += n;
|
|
|
|
}
|
|
|
|
/* full and right fringe blocks */
|
|
|
|
while(tot < count){
|
|
|
|
blk = getblock(offset+tot, r->ifcall.type==Twrite && nonzero);
|
|
|
|
n = BLKSZ;
|
|
|
|
if(n > count-tot)
|
|
|
|
n = count-tot;
|
|
|
|
if(r->ifcall.type != Twrite || blk != zero)
|
|
|
|
(*move)(dat+tot, blk, n);
|
|
|
|
if(r->ifcall.type == Twrite)
|
|
|
|
dirty(offset+tot, blk);
|
|
|
|
tot += n;
|
|
|
|
}
|
|
|
|
r->ofcall.count = tot;
|
|
|
|
respond(r, nil);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
fsread(Req *r)
|
|
|
|
{
|
|
|
|
char *s;
|
|
|
|
|
|
|
|
switch((int)r->fid->qid.path){
|
|
|
|
case Qroot:
|
|
|
|
dirread9p(r, rootgen, nil);
|
|
|
|
respond(r, nil);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Qdir:
|
|
|
|
dirread9p(r, dirgen, nil);
|
|
|
|
respond(r, nil);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Qctl:
|
|
|
|
s = ctlstring();
|
|
|
|
readstr(r, s);
|
|
|
|
free(s);
|
|
|
|
respond(r, nil);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
rdwrpart(r);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
fswrite(Req *r)
|
|
|
|
{
|
|
|
|
switch((int)r->fid->qid.path){
|
|
|
|
case Qroot:
|
|
|
|
case Qdir:
|
|
|
|
respond(r, "write to a directory?");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Qctl:
|
|
|
|
ctlwrite(r);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
rdwrpart(r);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
fsopen(Req *r)
|
|
|
|
{
|
|
|
|
if(r->ifcall.mode&ORCLOSE)
|
|
|
|
respond(r, "cannot open ORCLOSE");
|
|
|
|
|
|
|
|
switch((int)r->fid->qid.path){
|
|
|
|
case Qroot:
|
|
|
|
case Qdir:
|
|
|
|
if(r->ifcall.mode != OREAD){
|
|
|
|
respond(r, "bad mode for directory open");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
respond(r, nil);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
fsstat(Req *r)
|
|
|
|
{
|
|
|
|
int q;
|
|
|
|
Dir *d;
|
|
|
|
Part *p;
|
|
|
|
|
|
|
|
d = &r->d;
|
|
|
|
memset(d, 0, sizeof *d);
|
|
|
|
d->qid = r->fid->qid;
|
|
|
|
d->atime = d->mtime = time0;
|
|
|
|
q = r->fid->qid.path;
|
|
|
|
switch(q){
|
|
|
|
case Qroot:
|
|
|
|
d->name = estrdup9p("/");
|
|
|
|
d->mode = DMDIR|0777;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Qdir:
|
|
|
|
d->name = estrdup9p(sdname);
|
|
|
|
d->mode = DMDIR|0777;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
q -= Qpart;
|
|
|
|
if(q < 0 || q > nelem(tab) || tab[q].inuse==0 || r->fid->qid.vers != tab[q].vers){
|
|
|
|
respond(r, "partition no longer exists");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
p = &tab[q];
|
|
|
|
d->name = estrdup9p(p->name);
|
|
|
|
d->length = p->length * sectsize;
|
|
|
|
d->mode = p->mode;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
d->uid = estrdup9p("disksim");
|
|
|
|
d->gid = estrdup9p("disksim");
|
|
|
|
d->muid = estrdup9p("");
|
|
|
|
respond(r, nil);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
fsattach(Req *r)
|
|
|
|
{
|
|
|
|
char *spec;
|
|
|
|
|
|
|
|
spec = r->ifcall.aname;
|
|
|
|
if(spec && spec[0]){
|
|
|
|
respond(r, "invalid attach specifier");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
r->ofcall.qid = (Qid){Qroot, 0, QTDIR};
|
|
|
|
r->fid->qid = r->ofcall.qid;
|
|
|
|
respond(r, nil);
|
|
|
|
}
|
|
|
|
|
|
|
|
char*
|
|
|
|
fswalk1(Fid *fid, char *name, Qid *qid)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
switch((int)fid->qid.path){
|
|
|
|
case Qroot:
|
|
|
|
if(strcmp(name, sdname) == 0){
|
|
|
|
fid->qid.path = Qdir;
|
|
|
|
fid->qid.type = QTDIR;
|
|
|
|
*qid = fid->qid;
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Qdir:
|
|
|
|
if(strcmp(name, "ctl") == 0){
|
|
|
|
fid->qid.path = Qctl;
|
|
|
|
fid->qid.vers = 0;
|
|
|
|
fid->qid.type = 0;
|
|
|
|
*qid = fid->qid;
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
for(i=0; i<nelem(tab); i++){
|
|
|
|
if(tab[i].inuse && strcmp(tab[i].name, name) == 0){
|
|
|
|
fid->qid.path = i+Qpart;
|
|
|
|
fid->qid.vers = tab[i].vers;
|
|
|
|
fid->qid.type = 0;
|
|
|
|
*qid = fid->qid;
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return "file not found";
|
|
|
|
}
|
|
|
|
|
|
|
|
Srv fs = {
|
|
|
|
.attach= fsattach,
|
|
|
|
.open= fsopen,
|
|
|
|
.read= fsread,
|
|
|
|
.write= fswrite,
|
|
|
|
.stat= fsstat,
|
|
|
|
.walk1= fswalk1,
|
|
|
|
};
|
|
|
|
|
|
|
|
char *mtpt = "/dev";
|
|
|
|
char *srvname;
|
|
|
|
|
|
|
|
void
|
|
|
|
usage(void)
|
|
|
|
{
|
|
|
|
fprint(2, "usage: aux/disksim [-D] [-f file] [-s srvname] [-m mtpt] [sdXX]\n");
|
|
|
|
fprint(2, "\tdefault mtpt is /dev\n");
|
|
|
|
exits("usage");
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
main(int argc, char **argv)
|
|
|
|
{
|
|
|
|
char *file;
|
|
|
|
|
|
|
|
file = nil;
|
|
|
|
quotefmtinstall();
|
|
|
|
time0 = time(0);
|
|
|
|
|
|
|
|
ARGBEGIN{
|
|
|
|
case 'D':
|
|
|
|
chatty9p++;
|
|
|
|
break;
|
|
|
|
case 'f':
|
|
|
|
file = EARGF(usage());
|
|
|
|
break;
|
|
|
|
case 'r':
|
|
|
|
rdonly = 1;
|
|
|
|
break;
|
|
|
|
case 's':
|
|
|
|
srvname = EARGF(usage());
|
|
|
|
break;
|
|
|
|
case 'm':
|
|
|
|
mtpt = EARGF(usage());
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
usage();
|
|
|
|
}ARGEND
|
|
|
|
|
|
|
|
if(argc > 1)
|
|
|
|
usage();
|
|
|
|
if(argc == 1)
|
|
|
|
sdname = argv[0];
|
|
|
|
|
|
|
|
if(file){
|
|
|
|
if((fd = open(file, rdonly ? OREAD : ORDWR)) < 0)
|
|
|
|
sysfatal("open %s: %r", file);
|
|
|
|
}
|
|
|
|
|
|
|
|
inquiry = estrdup9p(inquiry);
|
|
|
|
tab[0].name = estrdup9p("data");
|
|
|
|
tab[0].inuse = 1;
|
|
|
|
tab[0].mode = 0666;
|
|
|
|
|
|
|
|
postmountsrv(&fs, srvname, mtpt, MBEFORE);
|
|
|
|
exits(nil);
|
|
|
|
}
|