lib9p/lib9p.c
2016-01-23 22:57:40 +01:00

366 lines
10 KiB
C

/*
* Copyright 2016 Jakub Klama <jceel@FreeBSD.org>
* All rights reserved
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted providing that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
/*
* Based on libixp code: ©2007-2010 Kris Maglione <maglione.k at Gmail>
*/
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include "lib9p.h"
#define N(ary) (sizeof(ary) / sizeof(*ary))
#define STRING_SIZE(s) (L9P_WORD + strlen(s))
#define QID_SIZE (L9P_BYTE + L9P_DWORD + L9P_QWORD)
static void l9p_puint(struct l9p_message *, enum l9p_integer_type, uint32_t *);
static inline void l9p_pu8(struct l9p_message *, uint8_t *);
static inline void l9p_pu16(struct l9p_message *, uint16_t *);
static inline void l9p_pu32(struct l9p_message *, uint32_t *);
static inline void l9p_pu64(struct l9p_message *, uint64_t *);
static void l9p_pustring(struct l9p_message *, char **s);
static void l9p_pustrings(struct l9p_message *, uint16_t *,char *[], size_t);
static void l9p_pudata(struct l9p_message *, uint8_t **, size_t);
static void l9p_puqid(struct l9p_message *, struct l9p_qid *);
static void l9p_puqids(struct l9p_message *, uint16_t *, struct l9p_qid *q,
size_t);
static void
l9p_puint(struct l9p_message *msg, enum l9p_integer_type size, uint32_t *val)
{
uint8_t *pos;
int v;
if(msg->lm_pos + size <= msg->lm_end) {
pos = (uint8_t*)msg->lm_pos;
switch (msg->lm_mode) {
case L9P_PACK:
v = *val;
switch (size) {
case L9P_DWORD:
pos[3] = v>>24;
pos[2] = v>>16;
case L9P_WORD:
pos[1] = v>>8;
case L9P_BYTE:
pos[0] = v;
break;
}
case L9P_UNPACK:
v = 0;
switch (size) {
case L9P_DWORD:
v |= pos[3]<<24;
v |= pos[2]<<16;
case L9P_WORD:
v |= pos[1]<<8;
case L9P_BYTE:
v |= pos[0];
break;
}
*val = v;
}
}
msg->lm_pos += size;
}
static inline void
l9p_pu8(struct l9p_message *msg, uint8_t *val)
{
uint32_t v;
v = *val;
l9p_puint(msg, L9P_BYTE, &v);
*val = (uint8_t)v;
}
static inline void
l9p_pu16(struct l9p_message *msg, uint16_t *val)
{
uint32_t v;
v = *val;
l9p_puint(msg, L9P_WORD, &v);
*val = (uint16_t)v;
}
static inline void
l9p_pu32(struct l9p_message *msg, uint32_t *val)
{
l9p_puint(msg, L9P_DWORD, val);
}
static inline void
l9p_pu64(struct l9p_message *msg, uint64_t *val)
{
uint32_t vl, vb;
vl = (uint)*val;
vb = (uint)(*val>>32);
l9p_puint(msg, L9P_DWORD, &vl);
l9p_puint(msg, L9P_DWORD, &vb);
*val = vl | ((uint64_t)vb<<32);
}
static void
l9p_pustring(struct l9p_message *msg, char **s)
{
uint16_t len;
if(msg->lm_mode == L9P_PACK)
len = strlen(*s);
l9p_pu16(msg, &len);
if (msg->lm_pos + len <= msg->lm_end) {
if (msg->lm_mode == L9P_UNPACK) {
*s = malloc(len + 1);
memcpy(*s, msg->lm_pos, len);
(*s)[len] = '\0';
} else
memcpy(msg->lm_pos, *s, len);
}
msg->lm_pos += len;
}
static void
l9p_pustrings(struct l9p_message *msg, uint16_t *num, char *strings[],
size_t max)
{
char *s;
uint i, size;
uint16_t len;
l9p_pu16(msg, num);
if (*num > max) {
msg->lm_pos = msg->lm_end+1;
return;
}
s = NULL;
if (msg->lm_mode == L9P_UNPACK) {
s = msg->lm_pos;
size = 0;
for (i = 0; i < *num; i++) {
l9p_pu16(msg, &len);
msg->lm_pos += len;
size += len;
if (msg->lm_pos > msg->lm_end)
return;
}
msg->lm_pos = s;
size += *num;
s = malloc(size);
}
for (i = 0; i < *num; i++) {
if (msg->lm_mode == L9P_PACK)
len = strlen(strings[i]);
l9p_pu16(msg, &len);
if (msg->lm_mode == L9P_UNPACK) {
memcpy(s, msg->lm_pos, len);
strings[i] = (char*)s;
s += len;
msg->lm_pos += len;
*s++ = '\0';
} else
l9p_pudata(msg, &strings[i], len);
}
}
static void
l9p_pudata(struct l9p_message *msg, uint8_t **data, size_t len)
{
if (msg->lm_pos + len <= msg->lm_end) {
if (msg->lm_mode == L9P_UNPACK) {
*data = malloc(len);
memcpy(*data, msg->lm_pos, len);
} else
memcpy(msg->lm_pos, *data, len);
}
msg->lm_pos += len;
}
static void
l9p_puqid(struct l9p_message *msg, struct l9p_qid *qid)
{
l9p_pu8(msg, &qid->type);
l9p_pu32(msg, &qid->version);
l9p_pu64(msg, &qid->path);
}
static void
l9p_puqids(struct l9p_message *msg, uint16_t *num, struct l9p_qid *qids,
size_t max)
{
int i;
l9p_pu16(msg, num);
if (*num > max) {
msg->lm_pos = msg->lm_end + 1;
return;
}
for (i = 0; i < *num; i++)
l9p_puqid(msg, &qids[i]);
}
void
l9p_pustat(struct l9p_message *msg, struct l9p_stat *stat)
{
uint16_t size;
if(msg->lm_mode == L9P_PACK)
size = l9p_sizeof_stat(stat) - 2;
l9p_pu16(msg, &size);
l9p_pu16(msg, &stat->type);
l9p_pu32(msg, &stat->dev);
l9p_puqid(msg, &stat->qid);
l9p_pu32(msg, &stat->mode);
l9p_pu32(msg, &stat->atime);
l9p_pu32(msg, &stat->mtime);
l9p_pu64(msg, &stat->length);
l9p_pustring(msg, &stat->name);
l9p_pustring(msg, &stat->uid);
l9p_pustring(msg, &stat->gid);
l9p_pustring(msg, &stat->muid);
}
int
l9p_pufcall(struct l9p_message *msg, union l9p_fcall *fcall)
{
l9p_pu8(msg, &fcall->hdr.type);
l9p_pu16(msg, &fcall->hdr.tag);
switch (fcall->hdr.type) {
case L9P_TVERSION:
case L9P_RVERSION:
l9p_pu32(msg, &fcall->version.msize);
l9p_pustring(msg, &fcall->version.version);
break;
case L9P_TAUTH:
l9p_pu32(msg, &fcall->tauth.afid);
l9p_pustring(msg, &fcall->tauth.uname);
l9p_pustring(msg, &fcall->tauth.aname);
break;
case L9P_RAUTH:
l9p_puqid(msg, &fcall->rauth.aqid);
break;
case L9P_RATTACH:
l9p_puqid(msg, &fcall->rattach.qid);
break;
case L9P_TATTACH:
l9p_pu32(msg, &fcall->hdr.fid);
l9p_pu32(msg, &fcall->tattach.afid);
l9p_pustring(msg, &fcall->tattach.uname);
l9p_pustring(msg, &fcall->tattach.aname);
break;
case L9P_RERROR:
l9p_pustring(msg, &fcall->error.ename);
break;
case L9P_TFLUSH:
l9p_pu16(msg, &fcall->tflush.oldtag);
break;
case L9P_TWALK:
l9p_pu32(msg, &fcall->hdr.fid);
l9p_pu32(msg, &fcall->twalk.newfid);
l9p_pustrings(msg, &fcall->twalk.nwname, fcall->twalk.wname,
N(fcall->twalk.wname));
break;
case L9P_RWALK:
l9p_puqids(msg, &fcall->rwalk.nwqid, fcall->rwalk.wqid,
N(fcall->rwalk.wqid));
break;
case L9P_TOPEN:
l9p_pu32(msg, &fcall->hdr.fid);
l9p_pu8(msg, &fcall->topen.mode);
break;
case L9P_ROPEN:
case L9P_RCREATE:
l9p_puqid(msg, &fcall->ropen.qid);
l9p_pu32(msg, &fcall->ropen.iounit);
break;
case L9P_TCREATE:
l9p_pu32(msg, &fcall->hdr.fid);
l9p_pustring(msg, &fcall->tcreate.name);
l9p_pu32(msg, &fcall->tcreate.perm);
l9p_pu8(msg, &fcall->tcreate.mode);
break;
case L9P_TREAD:
l9p_pu32(msg, &fcall->hdr.fid);
l9p_pu64(msg, &fcall->io.offset);
l9p_pu32(msg, &fcall->io.count);
break;
case L9P_RREAD:
l9p_pu32(msg, &fcall->io.count);
l9p_pudata(msg, &fcall->io.data, fcall->io.count);
break;
case L9P_TWRITE:
l9p_pu32(msg, &fcall->hdr.fid);
l9p_pu64(msg, &fcall->io.offset);
l9p_pu32(msg, &fcall->io.count);
l9p_pudata(msg, &fcall->io.data, fcall->io.count);
break;
case L9P_RWRITE:
l9p_pu32(msg, &fcall->io.count);
break;
case L9P_TCLUNK:
case L9P_TSTAT:
l9p_pu32(msg, &fcall->hdr.fid);
break;
case L9P_RSTAT:
l9p_pu16(msg, &fcall->rstat.nstat);
l9p_pudata(msg, (char**)&fcall->rstat.stat, fcall->rstat.nstat);
break;
case L9P_TWSTAT: {
uint16_t size;
l9p_pu32(msg, &fcall->hdr.fid);
l9p_pu16(msg, &size);
l9p_pustat(msg, &fcall->twstat.stat);
break;
}
}
return (0);
}
uint16_t
l9p_sizeof_stat(struct l9p_stat *stat) {
return L9P_WORD /* size */
+ L9P_WORD /* type */
+ L9P_DWORD /* dev */
+ QID_SIZE /* qid */
+ 3 * L9P_DWORD /* mode, atime, mtime */
+ L9P_DWORD /* length */
+ STRING_SIZE(stat->name)
+ STRING_SIZE(stat->uid)
+ STRING_SIZE(stat->gid)
+ STRING_SIZE(stat->muid);
}