|
|
@ -17,6 +17,10 @@ static const uint32_t HDRSZ = 7; // size of header |
|
|
|
static const uint32_t QIDSZ = 13; // size of serialized pi9_qid |
|
|
|
static const uint32_t STATHDRSZ = 47; // size of serialized pi9_stat, until the variable length data |
|
|
|
|
|
|
|
struct pi9_stream { |
|
|
|
struct chck_buffer out, in; |
|
|
|
}; |
|
|
|
|
|
|
|
enum op { |
|
|
|
OPFIRST, |
|
|
|
Tversion = 0x64, |
|
|
@ -50,7 +54,7 @@ enum op { |
|
|
|
OPLAST, |
|
|
|
}; |
|
|
|
|
|
|
|
#define DECOP(x) static bool op_##x(struct pi9 *pi9, uint16_t tag, struct chck_buffer *in, struct chck_buffer *out) |
|
|
|
#define DECOP(x) static bool op_##x(struct pi9 *pi9, uint16_t tag, struct pi9_stream *stream) |
|
|
|
DECOP(Tversion); |
|
|
|
DECOP(Tauth); |
|
|
|
DECOP(Tattach); |
|
|
@ -68,7 +72,7 @@ DECOP(Twstat); |
|
|
|
|
|
|
|
static struct { |
|
|
|
size_t msz; |
|
|
|
bool (*cb)(struct pi9 *pi9, uint16_t tag, struct chck_buffer *in, struct chck_buffer *out); |
|
|
|
bool (*cb)(struct pi9 *pi9, uint16_t tag, struct pi9_stream *stream); |
|
|
|
} ops[] = { |
|
|
|
[Tversion] = { 6, op_Tversion }, |
|
|
|
[Tauth] = { 8, op_Tauth }, |
|
|
@ -104,49 +108,49 @@ static const struct { |
|
|
|
}; |
|
|
|
|
|
|
|
static inline bool |
|
|
|
write_qid(struct pi9_qid *qid, struct chck_buffer *out) |
|
|
|
write_qid(struct pi9_qid *qid, struct pi9_stream *stream) |
|
|
|
{ |
|
|
|
return (chck_buffer_write_int(&qid->type, sizeof(qid->type), out) && |
|
|
|
chck_buffer_write_int(&qid->vers, sizeof(qid->vers), out) && |
|
|
|
chck_buffer_write_int(&qid->path, sizeof(qid->path), out)); |
|
|
|
return (chck_buffer_write_int(&qid->type, sizeof(qid->type), o">&stream->out) && |
|
|
|
chck_buffer_write_int(&qid->vers, sizeof(qid->vers), o">&stream->out) && |
|
|
|
chck_buffer_write_int(&qid->path, sizeof(qid->path), o">&stream->out)); |
|
|
|
} |
|
|
|
|
|
|
|
static inline bool |
|
|
|
read_qid(struct pi9_qid *qid, struct chck_buffer *in) |
|
|
|
read_qid(struct pi9_qid *qid, struct pi9_stream *stream) |
|
|
|
{ |
|
|
|
return (chck_buffer_read_int(&qid->type, sizeof(qid->type), in) && |
|
|
|
chck_buffer_read_int(&qid->vers, sizeof(qid->vers), in) && |
|
|
|
chck_buffer_read_int(&qid->path, sizeof(qid->path), in)); |
|
|
|
return (chck_buffer_read_int(&qid->type, sizeof(qid->type), o">&stream->in) && |
|
|
|
chck_buffer_read_int(&qid->vers, sizeof(qid->vers), o">&stream->in) && |
|
|
|
chck_buffer_read_int(&qid->path, sizeof(qid->path), o">&stream->in)); |
|
|
|
} |
|
|
|
|
|
|
|
static inline bool |
|
|
|
read_stat(struct pi9_stat *stat, struct chck_buffer *in) |
|
|
|
read_stat(struct pi9_stat *stat, struct pi9_stream *stream) |
|
|
|
{ |
|
|
|
uint16_t size; |
|
|
|
if (!chck_buffer_read_int(&size, sizeof(size), in) || |
|
|
|
!chck_buffer_read_int(&stat->type, sizeof(stat->type), in) || |
|
|
|
!chck_buffer_read_int(&stat->dev, sizeof(stat->dev), in) || |
|
|
|
!read_qid(&stat->qid, in) || |
|
|
|
!chck_buffer_read_int(&stat->mode, sizeof(stat->mode), in) || |
|
|
|
!chck_buffer_read_int(&stat->atime, sizeof(stat->atime), in) || |
|
|
|
!chck_buffer_read_int(&stat->mtime, sizeof(stat->mtime), in) || |
|
|
|
!chck_buffer_read_int(&stat->length, sizeof(stat->length), in)) |
|
|
|
if (!chck_buffer_read_int(&size, sizeof(size), o">&stream->in) || |
|
|
|
!chck_buffer_read_int(&stat->type, sizeof(stat->type), o">&stream->in) || |
|
|
|
!chck_buffer_read_int(&stat->dev, sizeof(stat->dev), o">&stream->in) || |
|
|
|
!read_qid(&stat->qid, stream) || |
|
|
|
!chck_buffer_read_int(&stat->mode, sizeof(stat->mode), o">&stream->in) || |
|
|
|
!chck_buffer_read_int(&stat->atime, sizeof(stat->atime), o">&stream->in) || |
|
|
|
!chck_buffer_read_int(&stat->mtime, sizeof(stat->mtime), o">&stream->in) || |
|
|
|
!chck_buffer_read_int(&stat->length, sizeof(stat->length), o">&stream->in)) |
|
|
|
return false; |
|
|
|
|
|
|
|
struct pi9_string *fields[4] = { &stat->name, &stat->uid, &stat->gid, &stat->muid }; |
|
|
|
for (uint32_t i = 0; i < 4; ++i) { |
|
|
|
uint16_t len; |
|
|
|
if (!chck_buffer_read_int(&len, sizeof(len), in)) |
|
|
|
if (!chck_buffer_read_int(&len, sizeof(len), o">&stream->in)) |
|
|
|
return false; |
|
|
|
|
|
|
|
pi9_string_set_cstr_with_length(fields[i], in->curpos, len, false); |
|
|
|
pi9_string_set_cstr_with_length(fields[i], stream->in.curpos, len, false); |
|
|
|
} |
|
|
|
|
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
static bool |
|
|
|
op_Tversion(struct pi9 *pi9, uint16_t tag, struct chck_buffer *in, struct chck_buffer *out) |
|
|
|
op_Tversion(struct pi9 *pi9, uint16_t tag, struct pi9_stream *stream) |
|
|
|
{ |
|
|
|
// tag should always be NOTAG in version messages |
|
|
|
if (tag != NOTAG) |
|
|
@ -154,8 +158,8 @@ op_Tversion(struct pi9 *pi9, uint16_t tag, struct chck_buffer *in, struct chck_b |
|
|
|
|
|
|
|
uint32_t msize; |
|
|
|
uint16_t vsize; |
|
|
|
if (!chck_buffer_read_int(&msize, sizeof(msize), in) || |
|
|
|
!chck_buffer_read_int(&vsize, sizeof(vsize), in)) |
|
|
|
if (!chck_buffer_read_int(&msize, sizeof(msize), o">&stream->in) || |
|
|
|
!chck_buffer_read_int(&vsize, sizeof(vsize), o">&stream->in)) |
|
|
|
goto err_read; |
|
|
|
|
|
|
|
#if VERBOSE |
|
|
@ -163,7 +167,7 @@ op_Tversion(struct pi9 *pi9, uint16_t tag, struct chck_buffer *in, struct chck_b |
|
|
|
#endif |
|
|
|
|
|
|
|
struct pi9_string version = {0}; |
|
|
|
pi9_string_set_cstr_with_length(&version, in->curpos, vsize, false); |
|
|
|
pi9_string_set_cstr_with_length(&version, stream->in.curpos, vsize, false); |
|
|
|
|
|
|
|
// A successful version request initializes the connection. |
|
|
|
// All outstanding I/O on the connection is aborted; all active fids are freed (`clunked') automatically. |
|
|
@ -177,41 +181,41 @@ op_Tversion(struct pi9 *pi9, uint16_t tag, struct chck_buffer *in, struct chck_b |
|
|
|
// only support 9P2000, maybe 9P2000.L later, .u probably never |
|
|
|
if (!pi9_string_eq_cstr(&version, "9P2000")) { |
|
|
|
static const char *preferred = "9P2000"; |
|
|
|
const char *reply = (vsize > 0 && pi9_cstrneq(version.data, "9P", (vsize >= 2 ? 2 : vsize)) ? preferred : "unknown"); |
|
|
|
const char *reply = (pi9_string_starts_with_cstr(&version, "9P") ? preferred : "unknown"); |
|
|
|
vsize = strlen(reply); |
|
|
|
const uint32_t size = HDRSZ + sizeof(msize) + sizeof(vsize) + vsize; |
|
|
|
if (!chck_buffer_write_int(&size, sizeof(size), out) || |
|
|
|
!chck_buffer_write_int((uint8_t[]){Rversion}, sizeof(uint8_t), out) || |
|
|
|
!chck_buffer_write_int(&tag, sizeof(tag), out) || |
|
|
|
!chck_buffer_write_int(&msize, sizeof(msize), out) || |
|
|
|
!chck_buffer_write_string_of_type(reply, vsize, sizeof(uint16_t), out)) |
|
|
|
if (!chck_buffer_write_int(&size, sizeof(size), o">&stream->out) || |
|
|
|
!chck_buffer_write_int((uint8_t[]){Rversion}, sizeof(uint8_t), o">&stream->out) || |
|
|
|
!chck_buffer_write_int(&tag, sizeof(tag), o">&stream->out) || |
|
|
|
!chck_buffer_write_int(&msize, sizeof(msize), o">&stream->out) || |
|
|
|
!chck_buffer_write_string_of_type(reply, vsize, sizeof(uint16_t), o">&stream->out)) |
|
|
|
goto err_write; |
|
|
|
} else { |
|
|
|
const size_t size = HDRSZ + sizeof(msize) + sizeof(vsize) + vsize; |
|
|
|
if (chck_buffer_write(in->buffer, 1, size, out) != size) |
|
|
|
if (chck_buffer_write(stream->in.buffer, 1, size, &stream->out) != size) |
|
|
|
goto err_write; |
|
|
|
|
|
|
|
*(uint8_t*)(out->buffer + sizeof(uint32_t)) = Rversion; |
|
|
|
*(uint8_t*)(stream->in.buffer + sizeof(uint32_t)) = Rversion; |
|
|
|
} |
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
err_read: |
|
|
|
pi9_write_error(tag, PI9_ERR_READ, out); |
|
|
|
pi9_write_error(tag, PI9_ERR_READ, stream); |
|
|
|
return false; |
|
|
|
err_write: |
|
|
|
pi9_write_error(tag, PI9_ERR_WRITE, out); |
|
|
|
pi9_write_error(tag, PI9_ERR_WRITE, stream); |
|
|
|
return false; |
|
|
|
err_not_allowed: |
|
|
|
pi9_write_error(tag, PI9_ERR_NOT_ALLOWED, out); |
|
|
|
pi9_write_error(tag, PI9_ERR_NOT_ALLOWED, stream); |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
static bool |
|
|
|
op_Tauth(struct pi9 *pi9, uint16_t tag, struct chck_buffer *in, struct chck_buffer *out) |
|
|
|
op_Tauth(struct pi9 *pi9, uint16_t tag, struct pi9_stream *stream) |
|
|
|
{ |
|
|
|
uint32_t afid; |
|
|
|
if (!chck_buffer_read_int(&afid, sizeof(afid), in)) |
|
|
|
if (!chck_buffer_read_int(&afid, sizeof(afid), o">&stream->in)) |
|
|
|
goto err_read; |
|
|
|
|
|
|
|
#if VERBOSE |
|
|
@ -219,19 +223,19 @@ op_Tauth(struct pi9 *pi9, uint16_t tag, struct chck_buffer *in, struct chck_buff |
|
|
|
#endif |
|
|
|
|
|
|
|
uint16_t usize; |
|
|
|
if (!chck_buffer_read_int(&usize, sizeof(usize), in)) |
|
|
|
if (!chck_buffer_read_int(&usize, sizeof(usize), o">&stream->in)) |
|
|
|
goto err_read; |
|
|
|
|
|
|
|
struct pi9_string uname = {0}; |
|
|
|
pi9_string_set_cstr_with_length(&uname, in->curpos, usize, false); |
|
|
|
chck_buffer_seek(in, usize, SEEK_CUR); |
|
|
|
pi9_string_set_cstr_with_length(&uname, stream->in.curpos, usize, false); |
|
|
|
chck_buffer_seek(o">&stream->in, usize, SEEK_CUR); |
|
|
|
|
|
|
|
uint16_t asize; |
|
|
|
if (!chck_buffer_read_int(&asize, sizeof(asize), in)) |
|
|
|
if (!chck_buffer_read_int(&asize, sizeof(asize), o">&stream->in)) |
|
|
|
goto err_read; |
|
|
|
|
|
|
|
struct pi9_string aname = {0}; |
|
|
|
pi9_string_set_cstr_with_length(&aname, in->curpos, asize, false); |
|
|
|
pi9_string_set_cstr_with_length(&aname, stream->in.curpos, asize, false); |
|
|
|
|
|
|
|
struct pi9_qid *qid = NULL; |
|
|
|
if (pi9->procs.auth && !pi9->procs.auth(pi9, tag, afid, &uname, &aname, &qid)) |
|
|
@ -241,31 +245,31 @@ op_Tauth(struct pi9 *pi9, uint16_t tag, struct chck_buffer *in, struct chck_buff |
|
|
|
goto err_no_auth; |
|
|
|
|
|
|
|
const uint32_t size = HDRSZ + QIDSZ; |
|
|
|
if (!chck_buffer_write_int(&size, sizeof(size), out) || |
|
|
|
!chck_buffer_write_int((uint8_t[]){Rauth}, sizeof(uint8_t), out) || |
|
|
|
!chck_buffer_write_int(&tag, sizeof(tag), out) || |
|
|
|
!write_qid(qid, out)) |
|
|
|
if (!chck_buffer_write_int(&size, sizeof(size), o">&stream->out) || |
|
|
|
!chck_buffer_write_int((uint8_t[]){Rauth}, sizeof(uint8_t), o">&stream->out) || |
|
|
|
!chck_buffer_write_int(&tag, sizeof(tag), o">&stream->out) || |
|
|
|
!write_qid(qid, stream)) |
|
|
|
goto err_write; |
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
err_read: |
|
|
|
pi9_write_error(tag, PI9_ERR_READ, out); |
|
|
|
pi9_write_error(tag, PI9_ERR_READ, stream); |
|
|
|
return false; |
|
|
|
err_write: |
|
|
|
pi9_write_error(tag, PI9_ERR_WRITE, out); |
|
|
|
pi9_write_error(tag, PI9_ERR_WRITE, stream); |
|
|
|
return false; |
|
|
|
err_no_auth: |
|
|
|
pi9_write_error(tag, PI9_ERR_NO_AUTH, out); |
|
|
|
pi9_write_error(tag, PI9_ERR_NO_AUTH, stream); |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
static bool |
|
|
|
op_Tattach(struct pi9 *pi9, uint16_t tag, struct chck_buffer *in, struct chck_buffer *out) |
|
|
|
op_Tattach(struct pi9 *pi9, uint16_t tag, struct pi9_stream *stream) |
|
|
|
{ |
|
|
|
uint32_t fid, afid; |
|
|
|
if (!chck_buffer_read_int(&fid, sizeof(fid), in) || |
|
|
|
!chck_buffer_read_int(&afid, sizeof(afid), in)) |
|
|
|
if (!chck_buffer_read_int(&fid, sizeof(fid), o">&stream->in) || |
|
|
|
!chck_buffer_read_int(&afid, sizeof(afid), o">&stream->in)) |
|
|
|
goto err_read; |
|
|
|
|
|
|
|
#if VERBOSE |
|
|
@ -273,46 +277,46 @@ op_Tattach(struct pi9 *pi9, uint16_t tag, struct chck_buffer *in, struct chck_bu |
|
|
|
#endif |
|
|
|
|
|
|
|
uint16_t usize; |
|
|
|
if (!chck_buffer_read_int(&usize, sizeof(usize), in)) |
|
|
|
if (!chck_buffer_read_int(&usize, sizeof(usize), o">&stream->in)) |
|
|
|
goto err_read; |
|
|
|
|
|
|
|
struct pi9_string uname = {0}; |
|
|
|
pi9_string_set_cstr_with_length(&uname, in->curpos, usize, false); |
|
|
|
chck_buffer_seek(in, usize, SEEK_CUR); |
|
|
|
pi9_string_set_cstr_with_length(&uname, stream->in.curpos, usize, false); |
|
|
|
chck_buffer_seek(o">&stream->in, usize, SEEK_CUR); |
|
|
|
|
|
|
|
uint16_t asize; |
|
|
|
if (!chck_buffer_read_int(&asize, sizeof(asize), in)) |
|
|
|
if (!chck_buffer_read_int(&asize, sizeof(asize), o">&stream->in)) |
|
|
|
goto err_read; |
|
|
|
|
|
|
|
struct pi9_string aname = {0}; |
|
|
|
pi9_string_set_cstr_with_length(&aname, in->curpos, asize, false); |
|
|
|
pi9_string_set_cstr_with_length(&aname, stream->in.curpos, asize, false); |
|
|
|
|
|
|
|
struct pi9_qid *qid = NULL; |
|
|
|
if (pi9->procs.attach && !pi9->procs.attach(pi9, tag, fid, afid, &uname, &aname, &qid)) |
|
|
|
return false; |
|
|
|
|
|
|
|
const uint32_t size = HDRSZ + QIDSZ; |
|
|
|
if (!chck_buffer_write_int(&size, sizeof(size), out) || |
|
|
|
!chck_buffer_write_int((uint8_t[]){Rattach}, sizeof(uint8_t), out) || |
|
|
|
!chck_buffer_write_int(&tag, sizeof(tag), out) || |
|
|
|
!write_qid(qid, out)) |
|
|
|
if (!chck_buffer_write_int(&size, sizeof(size), o">&stream->out) || |
|
|
|
!chck_buffer_write_int((uint8_t[]){Rattach}, sizeof(uint8_t), o">&stream->out) || |
|
|
|
!chck_buffer_write_int(&tag, sizeof(tag), o">&stream->out) || |
|
|
|
!write_qid(qid, stream)) |
|
|
|
goto err_write; |
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
err_read: |
|
|
|
pi9_write_error(tag, PI9_ERR_READ, out); |
|
|
|
pi9_write_error(tag, PI9_ERR_READ, stream); |
|
|
|
return false; |
|
|
|
err_write: |
|
|
|
pi9_write_error(tag, PI9_ERR_WRITE, out); |
|
|
|
pi9_write_error(tag, PI9_ERR_WRITE, stream); |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
static bool |
|
|
|
op_Tflush(struct pi9 *pi9, uint16_t tag, struct chck_buffer *in, struct chck_buffer *out) |
|
|
|
op_Tflush(struct pi9 *pi9, uint16_t tag, struct pi9_stream *stream) |
|
|
|
{ |
|
|
|
uint16_t oldtag; |
|
|
|
if (!chck_buffer_read_int(&oldtag, sizeof(oldtag), in)) |
|
|
|
if (!chck_buffer_read_int(&oldtag, sizeof(oldtag), o">&stream->in)) |
|
|
|
goto err_read; |
|
|
|
|
|
|
|
#if VERBOSE |
|
|
@ -327,29 +331,29 @@ op_Tflush(struct pi9 *pi9, uint16_t tag, struct chck_buffer *in, struct chck_buf |
|
|
|
// In either case, it should respond with an Rflush echoing the tag (not oldtag) of the Tflush message. |
|
|
|
// A Tflush can never be responded to by an Rerror message. |
|
|
|
|
|
|
|
if (!chck_buffer_write_int(&HDRSZ, sizeof(HDRSZ), out) || |
|
|
|
!chck_buffer_write_int((uint8_t[]){Rflush}, sizeof(uint8_t), out) || |
|
|
|
!chck_buffer_write_int(&tag, sizeof(tag), out)) |
|
|
|
if (!chck_buffer_write_int(&HDRSZ, sizeof(HDRSZ), o">&stream->out) || |
|
|
|
!chck_buffer_write_int((uint8_t[]){Rflush}, sizeof(uint8_t), o">&stream->out) || |
|
|
|
!chck_buffer_write_int(&tag, sizeof(tag), o">&stream->out)) |
|
|
|
goto err_write; |
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
err_read: |
|
|
|
pi9_write_error(tag, PI9_ERR_READ, out); |
|
|
|
pi9_write_error(tag, PI9_ERR_READ, stream); |
|
|
|
return false; |
|
|
|
err_write: |
|
|
|
pi9_write_error(tag, PI9_ERR_WRITE, out); |
|
|
|
pi9_write_error(tag, PI9_ERR_WRITE, stream); |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
static bool |
|
|
|
op_Twalk(struct pi9 *pi9, uint16_t tag, struct chck_buffer *in, struct chck_buffer *out) |
|
|
|
op_Twalk(struct pi9 *pi9, uint16_t tag, struct pi9_stream *stream) |
|
|
|
{ |
|
|
|
uint16_t nwname; |
|
|
|
uint32_t fid, newfid; |
|
|
|
if (!chck_buffer_read_int(&fid, sizeof(fid), in) || |
|
|
|
!chck_buffer_read_int(&newfid, sizeof(newfid), in) || |
|
|
|
!chck_buffer_read_int(&nwname, sizeof(nwname), in)) |
|
|
|
if (!chck_buffer_read_int(&fid, sizeof(fid), o">&stream->in) || |
|
|
|
!chck_buffer_read_int(&newfid, sizeof(newfid), o">&stream->in) || |
|
|
|
!chck_buffer_read_int(&nwname, sizeof(nwname), o">&stream->in)) |
|
|
|
goto err_read; |
|
|
|
|
|
|
|
#if VERBOSE |
|
|
@ -362,10 +366,10 @@ op_Twalk(struct pi9 *pi9, uint16_t tag, struct chck_buffer *in, struct chck_buff |
|
|
|
struct pi9_string walks[MAXWELEM] = {{0}}; |
|
|
|
for (uint32_t i = 0; i < MAXWELEM; ++i) { |
|
|
|
uint16_t len; |
|
|
|
if (!chck_buffer_read_int(&len, sizeof(len), in)) |
|
|
|
if (!chck_buffer_read_int(&len, sizeof(len), o">&stream->in)) |
|
|
|
goto err_read; |
|
|
|
|
|
|
|
pi9_string_set_cstr_with_length(&walks[i], in->curpos, len, false); |
|
|
|
pi9_string_set_cstr_with_length(&walks[i], stream->in.curpos, len, false); |
|
|
|
} |
|
|
|
|
|
|
|
uint16_t nwqid = 0; |
|
|
@ -377,37 +381,37 @@ op_Twalk(struct pi9 *pi9, uint16_t tag, struct chck_buffer *in, struct chck_buff |
|
|
|
assert(nwqid <= nwname); |
|
|
|
|
|
|
|
const uint32_t size = HDRSZ + sizeof(nwqid) + nwqid * QIDSZ; |
|
|
|
if (!chck_buffer_write_int(&size, sizeof(size), out) || |
|
|
|
!chck_buffer_write_int((uint8_t[]){Rwalk}, sizeof(uint8_t), out) || |
|
|
|
!chck_buffer_write_int(&tag, sizeof(tag), out) || |
|
|
|
!chck_buffer_write_int(&nwqid, sizeof(nwqid), out)) |
|
|
|
if (!chck_buffer_write_int(&size, sizeof(size), o">&stream->out) || |
|
|
|
!chck_buffer_write_int((uint8_t[]){Rwalk}, sizeof(uint8_t), o">&stream->out) || |
|
|
|
!chck_buffer_write_int(&tag, sizeof(tag), o">&stream->out) || |
|
|
|
!chck_buffer_write_int(&nwqid, sizeof(nwqid), o">&stream->out)) |
|
|
|
goto err_write; |
|
|
|
|
|
|
|
for (uint32_t i = 0; i < nwqid; ++i) { |
|
|
|
if (!write_qid(qids[i], out)) |
|
|
|
if (!write_qid(qids[i], stream)) |
|
|
|
goto err_write; |
|
|
|
} |
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
err_read: |
|
|
|
pi9_write_error(tag, PI9_ERR_READ, out); |
|
|
|
pi9_write_error(tag, PI9_ERR_READ, stream); |
|
|
|
return false; |
|
|
|
err_write: |
|
|
|
pi9_write_error(tag, PI9_ERR_WRITE, out); |
|
|
|
pi9_write_error(tag, PI9_ERR_WRITE, stream); |
|
|
|
return false; |
|
|
|
err_not_allowed: |
|
|
|
pi9_write_error(tag, PI9_ERR_NOT_ALLOWED, out); |
|
|
|
pi9_write_error(tag, PI9_ERR_NOT_ALLOWED, stream); |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
static bool |
|
|
|
op_Topen(struct pi9 *pi9, uint16_t tag, struct chck_buffer *in, struct chck_buffer *out) |
|
|
|
op_Topen(struct pi9 *pi9, uint16_t tag, struct pi9_stream *stream) |
|
|
|
{ |
|
|
|
uint8_t mode; |
|
|
|
uint32_t fid; |
|
|
|
if (!chck_buffer_read_int(&fid, sizeof(fid), in) || |
|
|
|
!chck_buffer_read_int(&mode, sizeof(mode), in)) |
|
|
|
if (!chck_buffer_read_int(&fid, sizeof(fid), o">&stream->in) || |
|
|
|
!chck_buffer_read_int(&mode, sizeof(mode), o">&stream->in)) |
|
|
|
goto err_read; |
|
|
|
|
|
|
|
// All other bits in mode should be zero |
|
|
@ -426,42 +430,42 @@ op_Topen(struct pi9 *pi9, uint16_t tag, struct chck_buffer *in, struct chck_buff |
|
|
|
goto err_not_allowed; |
|
|
|
|
|
|
|
const uint32_t size = HDRSZ + QIDSZ + sizeof(iounit); |
|
|
|
if (!chck_buffer_write_int(&size, sizeof(size), out) || |
|
|
|
!chck_buffer_write_int((uint8_t[]){Ropen}, sizeof(uint8_t), out) || |
|
|
|
!chck_buffer_write_int(&tag, sizeof(tag), out) || |
|
|
|
!write_qid(qid, out) || |
|
|
|
!chck_buffer_write_int(&iounit, sizeof(iounit), out)) |
|
|
|
if (!chck_buffer_write_int(&size, sizeof(size), o">&stream->out) || |
|
|
|
!chck_buffer_write_int((uint8_t[]){Ropen}, sizeof(uint8_t), o">&stream->out) || |
|
|
|
!chck_buffer_write_int(&tag, sizeof(tag), o">&stream->out) || |
|
|
|
!write_qid(qid, stream) || |
|
|
|
!chck_buffer_write_int(&iounit, sizeof(iounit), o">&stream->out)) |
|
|
|
goto err_write; |
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
err_read: |
|
|
|
pi9_write_error(tag, PI9_ERR_READ, out); |
|
|
|
pi9_write_error(tag, PI9_ERR_READ, stream); |
|
|
|
return false; |
|
|
|
err_write: |
|
|
|
pi9_write_error(tag, PI9_ERR_WRITE, out); |
|
|
|
pi9_write_error(tag, PI9_ERR_WRITE, stream); |
|
|
|
return false; |
|
|
|
err_not_allowed: |
|
|
|
pi9_write_error(tag, PI9_ERR_NOT_ALLOWED, out); |
|
|
|
pi9_write_error(tag, PI9_ERR_NOT_ALLOWED, stream); |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
static bool |
|
|
|
op_Tcreate(struct pi9 *pi9, uint16_t tag, struct chck_buffer *in, struct chck_buffer *out) |
|
|
|
op_Tcreate(struct pi9 *pi9, uint16_t tag, struct pi9_stream *stream) |
|
|
|
{ |
|
|
|
uint32_t fid; |
|
|
|
uint16_t nsize; |
|
|
|
if (!chck_buffer_read_int(&fid, sizeof(fid), in) || |
|
|
|
!chck_buffer_read_int(&nsize, sizeof(nsize), in)) |
|
|
|
if (!chck_buffer_read_int(&fid, sizeof(fid), o">&stream->in) || |
|
|
|
!chck_buffer_read_int(&nsize, sizeof(nsize), o">&stream->in)) |
|
|
|
goto err_read; |
|
|
|
|
|
|
|
struct pi9_string name = {0}; |
|
|
|
pi9_string_set_cstr_with_length(&name, in->curpos, nsize, false); |
|
|
|
pi9_string_set_cstr_with_length(&name, stream->in.curpos, nsize, false); |
|
|
|
|
|
|
|
uint8_t mode; |
|
|
|
uint32_t perm; |
|
|
|
if (!chck_buffer_read_int(&perm, sizeof(perm), in) || |
|
|
|
!chck_buffer_read_int(&mode, sizeof(mode), in)) |
|
|
|
if (!chck_buffer_read_int(&perm, sizeof(perm), o">&stream->in) || |
|
|
|
!chck_buffer_read_int(&mode, sizeof(mode), o">&stream->in)) |
|
|
|
goto err_read; |
|
|
|
|
|
|
|
#if VERBOSE |
|
|
@ -481,104 +485,104 @@ op_Tcreate(struct pi9 *pi9, uint16_t tag, struct chck_buffer *in, struct chck_bu |
|
|
|
goto err_not_allowed; |
|
|
|
|
|
|
|
const uint32_t size = HDRSZ + QIDSZ + sizeof(iounit); |
|
|
|
if (!chck_buffer_write_int(&size, sizeof(size), out) || |
|
|
|
!chck_buffer_write_int((uint8_t[]){Rcreate}, sizeof(uint8_t), out) || |
|
|
|
!chck_buffer_write_int(&tag, sizeof(tag), out) || |
|
|
|
!write_qid(qid, out) || |
|
|
|
!chck_buffer_write_int(&iounit, sizeof(iounit), out)) |
|
|
|
if (!chck_buffer_write_int(&size, sizeof(size), o">&stream->out) || |
|
|
|
!chck_buffer_write_int((uint8_t[]){Rcreate}, sizeof(uint8_t), o">&stream->out) || |
|
|
|
!chck_buffer_write_int(&tag, sizeof(tag), o">&stream->out) || |
|
|
|
!write_qid(qid, stream) || |
|
|
|
!chck_buffer_write_int(&iounit, sizeof(iounit), o">&stream->out)) |
|
|
|
goto err_write; |
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
err_read: |
|
|
|
pi9_write_error(tag, PI9_ERR_READ, out); |
|
|
|
pi9_write_error(tag, PI9_ERR_READ, stream); |
|
|
|
return false; |
|
|
|
err_write: |
|
|
|
pi9_write_error(tag, PI9_ERR_WRITE, out); |
|
|
|
pi9_write_error(tag, PI9_ERR_WRITE, stream); |
|
|
|
return false; |
|
|
|
err_not_allowed: |
|
|
|
pi9_write_error(tag, PI9_ERR_NOT_ALLOWED, out); |
|
|
|
pi9_write_error(tag, PI9_ERR_NOT_ALLOWED, stream); |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
static bool |
|
|
|
op_Tread(struct pi9 *pi9, uint16_t tag, struct chck_buffer *in, struct chck_buffer *out) |
|
|
|
op_Tread(struct pi9 *pi9, uint16_t tag, struct pi9_stream *stream) |
|
|
|
{ |
|
|
|
uint64_t offset; |
|
|
|
uint32_t fid, count; |
|
|
|
if (!chck_buffer_read_int(&fid, sizeof(fid), in) || |
|
|
|
!chck_buffer_read_int(&offset, sizeof(offset), in) || |
|
|
|
!chck_buffer_read_int(&count, sizeof(count), in)) |
|
|
|
if (!chck_buffer_read_int(&fid, sizeof(fid), o">&stream->in) || |
|
|
|
!chck_buffer_read_int(&offset, sizeof(offset), o">&stream->in) || |
|
|
|
!chck_buffer_read_int(&count, sizeof(count), o">&stream->in)) |
|
|
|
goto err_read; |
|
|
|
|
|
|
|
#if VERBOSE |
|
|
|
fprintf(stderr, "Tread %u %u %"PRIu64" %u\n", tag, fid, offset, count); |
|
|
|
#endif |
|
|
|
|
|
|
|
chck_buffer_seek(out, HDRSZ + sizeof(uint32_t), SEEK_SET); |
|
|
|
void *start = out->curpos; |
|
|
|
chck_buffer_seek(o">&stream->out, HDRSZ + sizeof(uint32_t), SEEK_SET); |
|
|
|
void *start = stream->out.curpos; |
|
|
|
|
|
|
|
if (pi9->procs.read && !pi9->procs.read(pi9, tag, fid, offset, count)) |
|
|
|
return false; |
|
|
|
|
|
|
|
const uint32_t sbufsz = (offset != 0 ? 0 : (out->curpos - start)); |
|
|
|
const uint32_t sbufsz = (offset != 0 ? 0 : (stream->out.curpos - start)); |
|
|
|
const uint32_t size = HDRSZ + sizeof(sbufsz) + sbufsz; |
|
|
|
chck_buffer_seek(out, 0, SEEK_SET); |
|
|
|
if (!chck_buffer_write_int(&size, sizeof(size), out) || |
|
|
|
!chck_buffer_write_int((uint8_t[]){Rread}, sizeof(uint8_t), out) || |
|
|
|
!chck_buffer_write_int(&tag, sizeof(tag), out) || |
|
|
|
!chck_buffer_write_int(&sbufsz, sizeof(sbufsz), out)) |
|
|
|
chck_buffer_seek(o">&stream->out, 0, SEEK_SET); |
|
|
|
if (!chck_buffer_write_int(&size, sizeof(size), o">&stream->out) || |
|
|
|
!chck_buffer_write_int((uint8_t[]){Rread}, sizeof(uint8_t), o">&stream->out) || |
|
|
|
!chck_buffer_write_int(&tag, sizeof(tag), o">&stream->out) || |
|
|
|
!chck_buffer_write_int(&sbufsz, sizeof(sbufsz), o">&stream->out)) |
|
|
|
goto err_write; |
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
err_read: |
|
|
|
pi9_write_error(tag, PI9_ERR_READ, out); |
|
|
|
pi9_write_error(tag, PI9_ERR_READ, stream); |
|
|
|
return false; |
|
|
|
err_write: |
|
|
|
pi9_write_error(tag, PI9_ERR_WRITE, out); |
|
|
|
pi9_write_error(tag, PI9_ERR_WRITE, stream); |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
static bool |
|
|
|
op_Twrite(struct pi9 *pi9, uint16_t tag, struct chck_buffer *in, struct chck_buffer *out) |
|
|
|
op_Twrite(struct pi9 *pi9, uint16_t tag, struct pi9_stream *stream) |
|
|
|
{ |
|
|
|
uint64_t offset; |
|
|
|
uint32_t fid, count; |
|
|
|
if (!chck_buffer_read_int(&fid, sizeof(fid), in) || |
|
|
|
!chck_buffer_read_int(&offset, sizeof(offset), in) || |
|
|
|
!chck_buffer_read_int(&count, sizeof(count), in)) |
|
|
|
if (!chck_buffer_read_int(&fid, sizeof(fid), o">&stream->in) || |
|
|
|
!chck_buffer_read_int(&offset, sizeof(offset), o">&stream->in) || |
|
|
|
!chck_buffer_read_int(&count, sizeof(count), o">&stream->in)) |
|
|
|
goto err_read; |
|
|
|
|
|
|
|
#if VERBOSE |
|
|
|
fprintf(stderr, "Twrite %u %"PRIu64" %u\n", fid, offset, count); |
|
|
|
#endif |
|
|
|
|
|
|
|
if (pi9->procs.write && !pi9->procs.write(pi9, tag, fid, offset, count, (count > 0 ? in->curpos : NULL))) |
|
|
|
if (pi9->procs.write && !pi9->procs.write(pi9, tag, fid, offset, count, (count > 0 ? stream->in.curpos : NULL))) |
|
|
|
return false; |
|
|
|
|
|
|
|
const uint32_t size = HDRSZ + sizeof(count); |
|
|
|
if (!chck_buffer_write_int(&size, sizeof(size), out) || |
|
|
|
!chck_buffer_write_int((uint8_t[]){Rwrite}, sizeof(uint8_t), out) || |
|
|
|
!chck_buffer_write_int(&tag, sizeof(tag), out) || |
|
|
|
!chck_buffer_write_int(&count, sizeof(count), out)) |
|
|
|
if (!chck_buffer_write_int(&size, sizeof(size), o">&stream->out) || |
|
|
|
!chck_buffer_write_int((uint8_t[]){Rwrite}, sizeof(uint8_t), o">&stream->out) || |
|
|
|
!chck_buffer_write_int(&tag, sizeof(tag), o">&stream->out) || |
|
|
|
!chck_buffer_write_int(&count, sizeof(count), o">&stream->out)) |
|
|
|
goto err_write; |
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
err_read: |
|
|
|
pi9_write_error(tag, PI9_ERR_READ, out); |
|
|
|
pi9_write_error(tag, PI9_ERR_READ, stream); |
|
|
|
return false; |
|
|
|
err_write: |
|
|
|
pi9_write_error(tag, PI9_ERR_WRITE, out); |
|
|
|
pi9_write_error(tag, PI9_ERR_WRITE, stream); |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
static bool |
|
|
|
op_Tclunk(struct pi9 *pi9, uint16_t tag, struct chck_buffer *in, struct chck_buffer *out) |
|
|
|
op_Tclunk(struct pi9 *pi9, uint16_t tag, struct pi9_stream *stream) |
|
|
|
{ |
|
|
|
uint32_t fid; |
|
|
|
if (!chck_buffer_read_int(&fid, sizeof(fid), in)) |
|
|
|
if (!chck_buffer_read_int(&fid, sizeof(fid), o">&stream->in)) |
|
|
|
goto err_read; |
|
|
|
|
|
|
|
#if VERBOSE |
|
|
@ -588,26 +592,26 @@ op_Tclunk(struct pi9 *pi9, uint16_t tag, struct chck_buffer *in, struct chck_buf |
|
|
|
if (pi9->procs.clunk && !pi9->procs.clunk(pi9, tag, fid)) |
|
|
|
return false; |
|
|
|
|
|
|
|
if (!chck_buffer_write_int(&HDRSZ, sizeof(HDRSZ), out) || |
|
|
|
!chck_buffer_write_int((uint8_t[]){Rclunk}, sizeof(uint8_t), out) || |
|
|
|
!chck_buffer_write_int(&tag, sizeof(tag), out)) |
|
|
|
if (!chck_buffer_write_int(&HDRSZ, sizeof(HDRSZ), o">&stream->out) || |
|
|
|
!chck_buffer_write_int((uint8_t[]){Rclunk}, sizeof(uint8_t), o">&stream->out) || |
|
|
|
!chck_buffer_write_int(&tag, sizeof(tag), o">&stream->out)) |
|
|
|
goto err_write; |
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
err_read: |
|
|
|
pi9_write_error(tag, PI9_ERR_READ, out); |
|
|
|
pi9_write_error(tag, PI9_ERR_READ, stream); |
|
|
|
return false; |
|
|
|
err_write: |
|
|
|
pi9_write_error(tag, PI9_ERR_WRITE, out); |
|
|
|
pi9_write_error(tag, PI9_ERR_WRITE, stream); |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
static bool |
|
|
|
op_Tremove(struct pi9 *pi9, uint16_t tag, struct chck_buffer *in, struct chck_buffer *out) |
|
|
|
op_Tremove(struct pi9 *pi9, uint16_t tag, struct pi9_stream *stream) |
|
|
|
{ |
|
|
|
uint32_t fid; |
|
|
|
if (!chck_buffer_read_int(&fid, sizeof(fid), in)) |
|
|
|
if (!chck_buffer_read_int(&fid, sizeof(fid), o">&stream->in)) |
|
|
|
goto err_read; |
|
|
|
|
|
|
|
#if VERBOSE |
|
|
@ -617,72 +621,72 @@ op_Tremove(struct pi9 *pi9, uint16_t tag, struct chck_buffer *in, struct chck_bu |
|
|
|
if (pi9->procs.remove && !pi9->procs.remove(pi9, tag, fid)) |
|
|
|
return false; |
|
|
|
|
|
|
|
if (!chck_buffer_write_int(&HDRSZ, sizeof(HDRSZ), out) || |
|
|
|
!chck_buffer_write_int((uint8_t[]){Rremove}, sizeof(uint8_t), out) || |
|
|
|
!chck_buffer_write_int(&tag, sizeof(tag), out)) |
|
|
|
if (!chck_buffer_write_int(&HDRSZ, sizeof(HDRSZ), o">&stream->out) || |
|
|
|
!chck_buffer_write_int((uint8_t[]){Rremove}, sizeof(uint8_t), o">&stream->out) || |
|
|
|
!chck_buffer_write_int(&tag, sizeof(tag), o">&stream->out)) |
|
|
|
goto err_write; |
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
err_read: |
|
|
|
pi9_write_error(tag, PI9_ERR_READ, out); |
|
|
|
pi9_write_error(tag, PI9_ERR_READ, stream); |
|
|
|
return false; |
|
|
|
err_write: |
|
|
|
pi9_write_error(tag, PI9_ERR_WRITE, out); |
|
|
|
pi9_write_error(tag, PI9_ERR_WRITE, stream); |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
static bool |
|
|
|
op_Tstat(struct pi9 *pi9, uint16_t tag, struct chck_buffer *in, struct chck_buffer *out) |
|
|
|
op_Tstat(struct pi9 *pi9, uint16_t tag, struct pi9_stream *stream) |
|
|
|
{ |
|
|
|
uint32_t fid; |
|
|
|
if (!chck_buffer_read_int(&fid, sizeof(fid), in)) |
|
|
|
if (!chck_buffer_read_int(&fid, sizeof(fid), o">&stream->in)) |
|
|
|
goto err_read; |
|
|
|
|
|
|
|
#if VERBOSE |
|
|
|
fprintf(stderr, "Tstat %u %u\n", tag, fid); |
|
|
|
#endif |
|
|
|
|
|
|
|
chck_buffer_seek(out, HDRSZ + sizeof(uint16_t), SEEK_SET); |
|
|
|
void *start = out->curpos; |
|
|
|
chck_buffer_seek(o">&stream->out, HDRSZ + sizeof(uint16_t), SEEK_SET); |
|
|
|
void *start = stream->out.curpos; |
|
|
|
|
|
|
|
struct pi9_stat *stat = NULL; |
|
|
|
if (pi9->procs.stat && !pi9->procs.stat(pi9, tag, fid, &stat)) |
|
|
|
return false; |
|
|
|
|
|
|
|
if (stat && !pi9_write_stat(stat, out)) |
|
|
|
if (stat && !pi9_write_stat(stat, stream)) |
|
|
|
goto err_write; |
|
|
|
|
|
|
|
// too big |
|
|
|
if (out->curpos - start > 0xFFFF) |
|
|
|
if (stream->out.curpos - start > 0xFFFF) |
|
|
|
goto err_write; |
|
|
|
|
|
|
|
const uint16_t sbufsz = (out->curpos - start); |
|
|
|
const uint16_t sbufsz = (stream->out.curpos - start); |
|
|
|
const uint32_t size = HDRSZ + sizeof(sbufsz) + sbufsz; |
|
|
|
chck_buffer_seek(out, 0, SEEK_SET); |
|
|
|
if (!chck_buffer_write_int(&size, sizeof(size), out) || |
|
|
|
!chck_buffer_write_int((uint8_t[]){Rstat}, sizeof(uint8_t), out) || |
|
|
|
!chck_buffer_write_int(&tag, sizeof(tag), out) || |
|
|
|
!chck_buffer_write_int(&sbufsz, sizeof(sbufsz), out)) |
|
|
|
chck_buffer_seek(o">&stream->out, 0, SEEK_SET); |
|
|
|
if (!chck_buffer_write_int(&size, sizeof(size), o">&stream->out) || |
|
|
|
!chck_buffer_write_int((uint8_t[]){Rstat}, sizeof(uint8_t), o">&stream->out) || |
|
|
|
!chck_buffer_write_int(&tag, sizeof(tag), o">&stream->out) || |
|
|
|
!chck_buffer_write_int(&sbufsz, sizeof(sbufsz), o">&stream->out)) |
|
|
|
goto err_write; |
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
err_read: |
|
|
|
pi9_write_error(tag, PI9_ERR_READ, out); |
|
|
|
pi9_write_error(tag, PI9_ERR_READ, stream); |
|
|
|
return false; |
|
|
|
err_write: |
|
|
|
pi9_write_error(tag, PI9_ERR_WRITE, out); |
|
|
|
pi9_write_error(tag, PI9_ERR_WRITE, stream); |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
static bool |
|
|
|
op_Twstat(struct pi9 *pi9, uint16_t tag, struct chck_buffer *in, struct chck_buffer *out) |
|
|
|
op_Twstat(struct pi9 *pi9, uint16_t tag, struct pi9_stream *stream) |
|
|
|
{ |
|
|
|
uint32_t fid; |
|
|
|
uint16_t sbufsz; |
|
|
|
if (!chck_buffer_read_int(&fid, sizeof(fid), in) || |
|
|
|
!chck_buffer_read_int(&sbufsz, sizeof(sbufsz), in)) |
|
|
|
if (!chck_buffer_read_int(&fid, sizeof(fid), o">&stream->in) || |
|
|
|
!chck_buffer_read_int(&sbufsz, sizeof(sbufsz), o">&stream->in)) |
|
|
|
goto err_read; |
|
|
|
|
|
|
|
#if VERBOSE |
|
|
@ -690,32 +694,32 @@ op_Twstat(struct pi9 *pi9, uint16_t tag, struct chck_buffer *in, struct chck_buf |
|
|
|
#endif |
|
|
|
|
|
|
|
struct pi9_stat stat = {0}; |
|
|
|
if (!read_stat(&stat, in)) |
|
|
|
if (!read_stat(&stat, stream)) |
|
|
|
goto err_read; |
|
|
|
|
|
|
|
if (pi9->procs.twstat && !pi9->procs.twstat(pi9, tag, fid, &stat)) |
|
|
|
return false; |
|
|
|
|
|
|
|
if (!chck_buffer_write_int(&HDRSZ, sizeof(HDRSZ), out) || |
|
|
|
!chck_buffer_write_int((uint8_t[]){Rwstat}, sizeof(uint8_t), out) || |
|
|
|
!chck_buffer_write_int(&tag, sizeof(tag), out)) |
|
|
|
if (!chck_buffer_write_int(&HDRSZ, sizeof(HDRSZ), o">&stream->out) || |
|
|
|
!chck_buffer_write_int((uint8_t[]){Rwstat}, sizeof(uint8_t), o">&stream->out) || |
|
|
|
!chck_buffer_write_int(&tag, sizeof(tag), o">&stream->out)) |
|
|
|
goto err_write; |
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
err_read: |
|
|
|
pi9_write_error(tag, PI9_ERR_READ, out); |
|
|
|
pi9_write_error(tag, PI9_ERR_READ, stream); |
|
|
|
return false; |
|
|
|
err_write: |
|
|
|
pi9_write_error(tag, PI9_ERR_WRITE, out); |
|
|
|
pi9_write_error(tag, PI9_ERR_WRITE, stream); |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
static inline bool |
|
|
|
call_op(struct pi9 *pi9, enum op op, uint16_t tag, struct chck_buffer *in, struct chck_buffer *out) |
|
|
|
call_op(struct pi9 *pi9, enum op op, uint16_t tag, struct pi9_stream *stream) |
|
|
|
{ |
|
|
|
// check opcode range, and only allow T opcodes (% 2), also check that message meets minimum size |
|
|
|
if (op <= OPFIRST || op >= OPLAST || op % 2 != 0 || in->size < ops[op].msz) |
|
|
|
if (op <= OPFIRST || op >= OPLAST || op % 2 != 0 || stream->in.size < ops[op].msz) |
|
|
|
goto err_unknown_op; |
|
|
|
|
|
|
|
if (op == Terror) { |
|
|
@ -725,68 +729,68 @@ call_op(struct pi9 *pi9, enum op op, uint16_t tag, struct chck_buffer *in, struc |
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
if (out->size < ops[op].msz && !chck_buffer_resize(out, ops[op].msz)) |
|
|
|
if (stream->out.size < ops[op].msz && !chck_buffer_resize(&stream->out, ops[op].msz)) |
|
|
|
goto err_write; |
|
|
|
|
|
|
|
return ops[op].cb(pi9, tag, in, out); |
|
|
|
return ops[op].cb(pi9, tag, stream); |
|
|
|
|
|
|
|
err_write: |
|
|
|
pi9_write_error(tag, PI9_ERR_WRITE, out); |
|
|
|
pi9_write_error(tag, PI9_ERR_WRITE, stream); |
|
|
|
return false; |
|
|
|
err_unknown_op: |
|
|
|
pi9_write_error(tag, PI9_ERR_UNKNOWN_OP, out); |
|
|
|
pi9_write_error(tag, PI9_ERR_UNKNOWN_OP, stream); |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
static bool |
|
|
|
read_msg(struct pi9 *pi9, int32_t fd, struct chck_buffer *in, struct chck_buffer *out) |
|
|
|
read_msg(struct pi9 *pi9, int32_t fd, struct pi9_stream *stream) |
|
|
|
{ |
|
|
|
assert(pi9 && fd >= 0); |
|
|
|
|
|
|
|
if (chck_buffer_fill_from_fd(fd, 1, pi9->msize, in) < HDRSZ) |
|
|
|
if (chck_buffer_fill_from_fd(fd, 1, pi9->msize, o">&stream->in) < HDRSZ) |
|
|
|
return false; |
|
|
|
|
|
|
|
uint32_t size; |
|
|
|
if (!chck_buffer_read_int(&size, sizeof(size), in) || size < HDRSZ) |
|
|
|
if (!chck_buffer_read_int(&size, sizeof(size), o">&stream->in) || size < HDRSZ) |
|
|
|
return false; |
|
|
|
|
|
|
|
if (in->size < size) { |
|
|
|
const size_t to_read = size - in->size; |
|
|
|
chck_buffer_seek(in, 0, SEEK_END); |
|
|
|
if (chck_buffer_fill_from_fd(fd, 1, to_read, in) < to_read) |
|
|
|
if (stream->in.size < size) { |
|
|
|
const size_t to_read = size - stream->in.size; |
|
|
|
chck_buffer_seek(o">&stream->in, 0, SEEK_END); |
|
|
|
if (chck_buffer_fill_from_fd(fd, 1, to_read, o">&stream->in) < to_read) |
|
|
|
return false; |
|
|
|
chck_buffer_seek(in, sizeof(size), SEEK_SET); |
|
|
|
chck_buffer_seek(o">&stream->in, sizeof(size), SEEK_SET); |
|
|
|
} |
|
|
|
|
|
|
|
uint8_t op; |
|
|
|
uint16_t tag; |
|
|
|
if (!chck_buffer_read_int(&op, sizeof(uint8_t), in) || |
|
|
|
!chck_buffer_read_int(&tag, sizeof(uint16_t), in)) |
|
|
|
if (!chck_buffer_read_int(&op, sizeof(uint8_t), o">&stream->in) || |
|
|
|
!chck_buffer_read_int(&tag, sizeof(uint16_t), o">&stream->in)) |
|
|
|
return false; |
|
|
|
|
|
|
|
#if VERBOSE |
|
|
|
fprintf(stderr, "Read message of size: %u (%u : %u)\n", size, op, tag); |
|
|
|
#endif |
|
|
|
for (uint32_t i = 0; i < size; ++i) |
|
|
|
putc(*(char*)(in->buffer + i), stderr); |
|
|
|
putc(*(char*)(stream->in.buffer + i), stderr); |
|
|
|
putc('\n', stderr); |
|
|
|
#endif |
|
|
|
|
|
|
|
return call_op(pi9, op, tag, in, out); |
|
|
|
return call_op(pi9, op, tag, stream); |
|
|
|
} |
|
|
|
|
|
|
|
static inline bool |
|
|
|
write_msg(int32_t fd, struct chck_buffer *out) |
|
|
|
write_msg(int32_t fd, struct pi9_stream *stream) |
|
|
|
{ |
|
|
|
assert(fd >= 0 && out->buffer); |
|
|
|
const uint32_t size = *(uint32_t*)out->buffer; |
|
|
|
assert(fd >= 0 && stream->out.buffer); |
|
|
|
const uint32_t size = *(uint32_t*)stream->out.buffer; |
|
|
|
#if VERBOSE |
|
|
|
fprintf(stderr, "Write message of size: %u\n", size); |
|
|
|
#endif |
|
|
|
return write(fd, out->buffer, size) == size; |
|
|
|
return write(fd, stream->out.buffer, size) == size; |
|
|
|
} |
|
|
|
|
|
|
|
bool |
|
|
|
pi9_write_stat(struct pi9_stat *stat, struct chck_buffer *out) |
|
|
|
pi9_write_stat(struct pi9_stat *stat, struct pi9_stream *stream) |
|
|
|
{ |
|
|
|
const size_t size = STATHDRSZ + stat->name.size + stat->uid.size + stat->gid.size + stat->muid.size; |
|
|
|
|
|
|
@ -795,24 +799,24 @@ pi9_write_stat(struct pi9_stat *stat, struct chck_buffer *out) |
|
|
|
return false; |
|
|
|
|
|
|
|
const uint16_t size16 = size; |
|
|
|
return (chck_buffer_write_int(&size16, sizeof(size16), out) && |
|
|
|
chck_buffer_write_int(&stat->type, sizeof(stat->type), out) && |
|
|
|
chck_buffer_write_int(&stat->dev, sizeof(stat->dev), out) && |
|
|
|
write_qid(&stat->qid, out) && |
|
|
|
chck_buffer_write_int(&stat->mode, sizeof(stat->mode), out) && |
|
|
|
chck_buffer_write_int(&stat->atime, sizeof(stat->atime), out) && |
|
|
|
chck_buffer_write_int(&stat->mtime, sizeof(stat->mtime), out) && |
|
|
|
chck_buffer_write_int(&stat->length, sizeof(stat->length), out) && |
|
|
|
chck_buffer_write_string_of_type(stat->name.data, stat->name.size, sizeof(uint16_t), out) && |
|
|
|
chck_buffer_write_string_of_type(stat->uid.data, stat->uid.size, sizeof(uint16_t), out) && |
|
|
|
chck_buffer_write_string_of_type(stat->gid.data, stat->gid.size, sizeof(uint16_t), out) && |
|
|
|
chck_buffer_write_string_of_type(stat->muid.data, stat->muid.size, sizeof(uint16_t), out)); |
|
|
|
return (chck_buffer_write_int(&size16, sizeof(size16), o">&stream->out) && |
|
|
|
chck_buffer_write_int(&stat->type, sizeof(stat->type), o">&stream->out) && |
|
|
|
chck_buffer_write_int(&stat->dev, sizeof(stat->dev), o">&stream->out) && |
|
|
|
write_qid(&stat->qid, stream) && |
|
|
|
chck_buffer_write_int(&stat->mode, sizeof(stat->mode), o">&stream->out) && |
|
|
|
chck_buffer_write_int(&stat->atime, sizeof(stat->atime), o">&stream->out) && |
|
|
|
chck_buffer_write_int(&stat->mtime, sizeof(stat->mtime), o">&stream->out) && |
|
|
|
chck_buffer_write_int(&stat->length, sizeof(stat->length), o">&stream->out) && |
|
|
|
chck_buffer_write_string_of_type(stat->name.data, stat->name.size, sizeof(uint16_t), o">&stream->out) && |
|
|
|
chck_buffer_write_string_of_type(stat->uid.data, stat->uid.size, sizeof(uint16_t), o">&stream->out) && |
|
|
|
chck_buffer_write_string_of_type(stat->gid.data, stat->gid.size, sizeof(uint16_t), o">&stream->out) && |
|
|
|
chck_buffer_write_string_of_type(stat->muid.data, stat->muid.size, sizeof(uint16_t), o">&stream->out)); |
|
|
|
} |
|
|
|
|
|
|
|
size_t |
|
|
|
pi9_write(const void *src, size_t size, size_t nmemb, struct chck_buffer *out) |
|
|
|
pi9_write(const void *src, size_t size, size_t nmemb, struct pi9_stream *stream) |
|
|
|
{ |
|
|
|
return chck_buffer_write(src, size, nmemb, out); |
|
|
|
return chck_buffer_write(src, size, nmemb, o">&stream->out); |
|
|
|
} |
|
|
|
|
|
|
|
void |
|
|
@ -829,21 +833,21 @@ pi9_stat_release(struct pi9_stat *stat) |
|
|
|
bool |
|
|
|
pi9_process(struct pi9 *pi9, int32_t fd) |
|
|
|
{ |
|
|
|
assert(pi9 && fd >= 0 && pi9->in && pi9->out); |
|
|
|
assert(pi9 && fd >= 0 && pi9->stream); |
|
|
|
|
|
|
|
chck_buffer_seek(pi9->in, 0, SEEK_SET); |
|
|
|
chck_buffer_seek(pi9->out, 0, SEEK_SET); |
|
|
|
chck_buffer_seek(o">&pi9->stream->in, 0, SEEK_SET); |
|
|
|
chck_buffer_seek(o">&pi9->stream->out, 0, SEEK_SET); |
|
|
|
|
|
|
|
bool ret = true; |
|
|
|
if (!read_msg(pi9, fd, pi9->in, pi9->out)) { |
|
|
|
if (pi9->out->curpos == pi9->out->buffer) |
|
|
|
pi9_write_error(NOTAG, PI9_ERR_READ, pi9->out); |
|
|
|
if (!read_msg(pi9, fd, pi9->stream)) { |
|
|
|
if (pi9->stream->out.curpos == pi9->stream->out.buffer) |
|
|
|
pi9_write_error(NOTAG, PI9_ERR_READ, pi9->stream); |
|
|
|
ret = false; |
|
|
|
} |
|
|
|
|
|
|
|
if (!write_msg(fd, pi9->out)) { |
|
|
|
pi9_write_error(NOTAG, PI9_ERR_WRITE, pi9->out); |
|
|
|
write_msg(fd, pi9->out); |
|
|
|
if (!write_msg(fd, pi9->stream)) { |
|
|
|
pi9_write_error(NOTAG, PI9_ERR_WRITE, pi9->stream); |
|
|
|
write_msg(fd, pi9->stream); |
|
|
|
ret = false; |
|
|
|
} |
|
|
|
|
|
|
@ -856,8 +860,9 @@ pi9_release(struct pi9 *pi9) |
|
|
|
if (!pi9) |
|
|
|
return; |
|
|
|
|
|
|
|
chck_buffer_release(pi9->out); |
|
|
|
chck_buffer_release(pi9->in); |
|
|
|
chck_buffer_release(&pi9->stream->out); |
|
|
|
chck_buffer_release(&pi9->stream->in); |
|
|
|
free(pi9->stream); |
|
|
|
memset(pi9, 0, sizeof(struct pi9)); |
|
|
|
} |
|
|
|
|
|
|
@ -870,16 +875,13 @@ pi9_init(struct pi9 *pi9, uint32_t msize, struct pi9_procs *procs, void *userdat |
|
|
|
pi9->msize = (msize > 0 ? msize : 8192); |
|
|
|
pi9->userdata = userdata; |
|
|
|
|
|
|
|
if (!(pi9->in = malloc(sizeof(struct chck_buffer)))) |
|
|
|
goto fail; |
|
|
|
|
|
|
|
if (!(pi9->out = malloc(sizeof(struct chck_buffer)))) |
|
|
|
if (!(pi9->stream = calloc(1, sizeof(struct pi9_stream)))) |
|
|
|
goto fail; |
|
|
|
|
|
|
|
if (!chck_buffer(pi9->in, pi9->msize, CHCK_ENDIANESS_LITTLE)) |
|
|
|
if (!chck_buffer(&pi9->stream->in, pi9->msize, CHCK_ENDIANESS_LITTLE)) |
|
|
|
goto fail; |
|
|
|
|
|
|
|
if (!chck_buffer(pi9->out, pi9->msize, CHCK_ENDIANESS_LITTLE)) |
|
|
|
if (!chck_buffer(o">&pi9->stream->out, pi9->msize, CHCK_ENDIANESS_LITTLE)) |
|
|
|
goto fail; |
|
|
|
|
|
|
|
return true; |
|
|
@ -892,14 +894,14 @@ fail: |
|
|
|
#undef pi9_write_error |
|
|
|
|
|
|
|
void |
|
|
|
pi9_write_error(uint16_t tag, enum pi9_error error, struct chck_buffer *out) |
|
|
|
pi9_write_error(uint16_t tag, enum pi9_error error, struct pi9_stream *stream) |
|
|
|
{ |
|
|
|
assert(out); |
|
|
|
assert(stream); |
|
|
|
const int32_t size = HDRSZ + sizeof(uint16_t) + errors[error].size; |
|
|
|
chck_buffer_seek(out, 0, SEEK_SET); |
|
|
|
chck_buffer_write_int(&size, sizeof(size), out); |
|
|
|
chck_buffer_write_int((uint8_t[]){ Rerror }, sizeof(uint8_t), out); |
|
|
|
chck_buffer_write_int(&tag, sizeof(tag), out); |
|
|
|
chck_buffer_write_string_of_type(errors[error].msg, errors[error].size, sizeof(uint16_t), out); |
|
|
|
chck_buffer_seek(o">&stream->out, 0, SEEK_SET); |
|
|
|
chck_buffer_write_int(&size, sizeof(size), o">&stream->out); |
|
|
|
chck_buffer_write_int((uint8_t[]){ Rerror }, sizeof(uint8_t), o">&stream->out); |
|
|
|
chck_buffer_write_int(&tag, sizeof(tag), o">&stream->out); |
|
|
|
chck_buffer_write_string_of_type(errors[error].msg, errors[error].size, sizeof(uint16_t), o">&stream->out); |
|
|
|
fprintf(stderr, "%s\n", errors[error].msg); |
|
|
|
} |