/*
* linux/fs/9p/conv.c
*
* 9P protocol conversion functions
*
* Copyright (C) 2004, 2005 by Latchesar Ionkov <lucho@ionkov.net>
* Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
* Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to:
* Free Software Foundation
* 51 Franklin Street, Fifth Floor
* Boston, MA 02111-1301 USA
*
*/
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/idr.h>
#include <asm/uaccess.h>
#include "debug.h"
#include "v9fs.h"
#include "9p.h"
#include "conv.h"
/*
* Buffer to help with string parsing
*/
struct cbuf {
unsigned char *sp;
unsigned char *p;
unsigned char *ep;
};
static inline void buf_init(struct cbuf *buf, void *data, int datalen)
{
buf->sp = buf->p = data;
buf->ep = data + datalen;
}
static inline int buf_check_overflow(struct cbuf *buf)
{
return buf->p > buf->ep;
}
static int buf_check_size(struct cbuf *buf, int len)
{
if (buf->p + len > buf->ep) {
if (buf->p < buf->ep) {
eprintk(KERN_ERR, "buffer overflow: want %d has %d\n",
len, (int)(buf->ep - buf->p));
dump_stack();
buf->p = buf->ep + 1;
}
return 0;
}
return 1;
}
static void *buf_alloc(struct cbuf *buf, int len)
{
void *ret = NULL;
if (buf_check_size(buf, len)) {
ret = buf->p;
buf->p += len;
}
return ret;
}
static void buf_put_int8(struct cbuf *buf, u8 val)
{
if (buf_check_size(buf, 1)) {
buf->p[0] = val;
buf->p++;
}
}
static void buf_put_int16(struct cbuf *buf, u16 val)
{
if (buf_check_size(buf, 2)) {
*(__le16 *) buf->p = cpu_to_le16(val);
buf->p += 2;
}
}
static void buf_put_int32(struct cbuf *buf, u32 val)
{
if (buf_check_size(buf, 4)) {
*(__le32 *)buf->p = cpu_to_le32(val);
buf->p += 4;
}
}
static void buf_put_int64(struct cbuf *buf, u64 val)
{
if (buf_check_size(buf, 8)) {
*(__le64 *)buf->p = cpu_to_le64(val);
buf->p += 8;
}
}
static char *buf_put_stringn(struct cbuf *buf, const char *s, u16 slen)
{
char *ret;
ret = NULL;
if (buf_check_size(buf, slen + 2)) {
buf_put_int16(buf, slen);
ret = buf->p;
memcpy(buf->p, s, slen);
buf->p += slen;
}
return ret;
}
static inline void buf_put_string(struct cbuf *buf, const char *s)
{
buf_put_stringn(buf, s, strlen(s));
}
static u8 buf_get_int8(struct cbuf *buf)
{
u8 ret = 0;
if (buf_check_size(buf, 1)) {
ret = buf->p[0];
buf->p++;
}
return ret;
}
static u16 buf_get_int16(struct cbuf *buf)
{
u16 ret = 0;
if (buf_check_size(buf, 2)) {
ret = le16_to_cpu(*(__le16 *)buf->p);
buf->p += 2;
}
return ret;
}
static u32 buf_get_int32(struct cbuf *buf)
{
u32 ret = 0;
if (buf_check_size(buf, 4)) {
ret = le32_to_cpu(*(__le32 *)buf->p);
buf->p += 4;
}
return ret;
}
static u64 buf_get_int64(struct cbuf *buf)
{
u64 ret = 0;
if (buf_check_size(buf, 8)) {
ret = le64_to_cpu(*(__le64 *)buf->p);
buf->p += 8;
}
return ret;
}
static void buf_get_str(struct cbuf *buf, struct v9fs_str *vstr)
{
vstr->len = buf_get_int16(buf);
if (!buf_check_overflow(buf) && buf_check_size(b