📄 conv.c
字号:
/* * net/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/sched.h>#include <linux/idr.h>#include <linux/uaccess.h>#include <net/9p/9p.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) { P9_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 p9_str *vstr){ vstr->len = buf_get_int16(buf); if (!buf_check_overflow(buf) && buf_check_size(buf, vstr->len)) { vstr->str = buf->p; buf->p += vstr->len; } else { vstr->len = 0; vstr->str = NULL; }}static void buf_get_qid(struct cbuf *bufp, struct p9_qid *qid){ qid->type = buf_get_int8(bufp); qid->version = buf_get_int32(bufp); qid->path = buf_get_int64(bufp);}/** * p9_size_wstat - calculate the size of a variable length stat struct * @stat: metadata (stat) structure * @dotu: non-zero if 9P2000.u * */static int p9_size_wstat(struct p9_wstat *wstat, int dotu){ int size = 0; if (wstat == NULL) { P9_EPRINTK(KERN_ERR, "p9_size_stat: got a NULL stat pointer\n"); return 0; } size = /* 2 + *//* size[2] */ 2 + /* type[2] */ 4 + /* dev[4] */ 1 + /* qid.type[1] */ 4 + /* qid.vers[4] */ 8 + /* qid.path[8] */ 4 + /* mode[4] */ 4 + /* atime[4] */ 4 + /* mtime[4] */ 8 + /* length[8] */ 8; /* minimum sum of string lengths */ if (wstat->name) size += strlen(wstat->name); if (wstat->uid) size += strlen(wstat->uid); if (wstat->gid) size += strlen(wstat->gid); if (wstat->muid) size += strlen(wstat->muid); if (dotu) { size += 4 + /* n_uid[4] */ 4 + /* n_gid[4] */ 4 + /* n_muid[4] */ 2; /* string length of extension[4] */ if (wstat->extension) size += strlen(wstat->extension); } return size;}/** * buf_get_stat - safely decode a recieved metadata (stat) structure * @bufp: buffer to deserialize * @stat: metadata (stat) structure * @dotu: non-zero if 9P2000.u * */static voidbuf_get_stat(struct cbuf *bufp, struct p9_stat *stat, int dotu){ stat->size = buf_get_int16(bufp); stat->type = buf_get_int16(bufp); stat->dev = buf_get_int32(bufp); stat->qid.type = buf_get_int8(bufp); stat->qid.version = buf_get_int32(bufp); stat->qid.path = buf_get_int64(bufp); stat->mode = buf_get_int32(bufp); stat->atime = buf_get_int32(bufp); stat->mtime = buf_get_int32(bufp); stat->length = buf_get_int64(bufp); buf_get_str(bufp, &stat->name); buf_get_str(bufp, &stat->uid); buf_get_str(bufp, &stat->gid); buf_get_str(bufp, &stat->muid); if (dotu) { buf_get_str(bufp, &stat->extension); stat->n_uid = buf_get_int32(bufp); stat->n_gid = buf_get_int32(bufp); stat->n_muid = buf_get_int32(bufp); }}/** * p9_deserialize_stat - decode a received metadata structure * @buf: buffer to deserialize * @buflen: length of received buffer * @stat: metadata structure to decode into * @dotu: non-zero if 9P2000.u * * Note: stat will point to the buf region. */intp9_deserialize_stat(void *buf, u32 buflen, struct p9_stat *stat, int dotu){ struct cbuf buffer; struct cbuf *bufp = &buffer; unsigned char *p; buf_init(bufp, buf, buflen); p = bufp->p; buf_get_stat(bufp, stat, dotu); if (buf_check_overflow(bufp)) return 0; else return bufp->p - p;}EXPORT_SYMBOL(p9_deserialize_stat);/** * deserialize_fcall - unmarshal a response * @buf: recieved buffer * @buflen: length of received buffer * @rcall: fcall structure to populate * @rcalllen: length of fcall structure to populate * @dotu: non-zero if 9P2000.u * */intp9_deserialize_fcall(void *buf, u32 buflen, struct p9_fcall *rcall, int dotu){ struct cbuf buffer; struct cbuf *bufp = &buffer; int i = 0; buf_init(bufp, buf, buflen); rcall->size = buf_get_int32(bufp); rcall->id = buf_get_int8(bufp); rcall->tag = buf_get_int16(bufp); P9_DPRINTK(P9_DEBUG_CONV, "size %d id %d tag %d\n", rcall->size, rcall->id, rcall->tag); switch (rcall->id) { default: P9_EPRINTK(KERN_ERR, "unknown message type: %d\n", rcall->id); return -EPROTO; case P9_RVERSION: rcall->params.rversion.msize = buf_get_int32(bufp); buf_get_str(bufp, &rcall->params.rversion.version); break; case P9_RFLUSH: break; case P9_RATTACH: rcall->params.rattach.qid.type = buf_get_int8(bufp); rcall->params.rattach.qid.version = buf_get_int32(bufp); rcall->params.rattach.qid.path = buf_get_int64(bufp); break; case P9_RWALK: rcall->params.rwalk.nwqid = buf_get_int16(bufp); if (rcall->params.rwalk.nwqid > P9_MAXWELEM) { P9_EPRINTK(KERN_ERR, "Rwalk with more than %d qids: %d\n", P9_MAXWELEM, rcall->params.rwalk.nwqid); return -EPROTO; } for (i = 0; i < rcall->params.rwalk.nwqid; i++) buf_get_qid(bufp, &rcall->params.rwalk.wqids[i]); break; case P9_ROPEN: buf_get_qid(bufp, &rcall->params.ropen.qid); rcall->params.ropen.iounit = buf_get_int32(bufp); break; case P9_RCREATE: buf_get_qid(bufp, &rcall->params.rcreate.qid); rcall->params.rcreate.iounit = buf_get_int32(bufp); break; case P9_RREAD: rcall->params.rread.count = buf_get_int32(bufp); rcall->params.rread.data = bufp->p; buf_check_size(bufp, rcall->params.rread.count); break; case P9_RWRITE: rcall->params.rwrite.count = buf_get_int32(bufp); break; case P9_RCLUNK: break; case P9_RREMOVE: break; case P9_RSTAT: buf_get_int16(bufp); buf_get_stat(bufp, &rcall->params.rstat.stat, dotu); break; case P9_RWSTAT: break; case P9_RERROR: buf_get_str(bufp, &rcall->params.rerror.error); if (dotu) rcall->params.rerror.errno = buf_get_int16(bufp); break; } if (buf_check_overflow(bufp)) { P9_DPRINTK(P9_DEBUG_ERROR, "buffer overflow\n"); return -EIO; } return bufp->p - bufp->sp;}EXPORT_SYMBOL(p9_deserialize_fcall);static inline void p9_put_int8(struct cbuf *bufp, u8 val, u8 * p){ *p = val; buf_put_int8(bufp, val);}static inline void p9_put_int16(struct cbuf *bufp, u16 val, u16 * p){ *p = val; buf_put_int16(bufp, val);}static inline void p9_put_int32(struct cbuf *bufp, u32 val, u32 * p){ *p = val; buf_put_int32(bufp, val);}static inline void p9_put_int64(struct cbuf *bufp, u64 val, u64 * p){ *p = val; buf_put_int64(bufp, val);}static voidp9_put_str(struct cbuf *bufp, char *data, struct p9_str *str){ int len; char *s; if (data) len = strlen(data); else len = 0; s = buf_put_stringn(bufp, data, len); if (str) { str->len = len; str->str = s; }}static intp9_put_data(struct cbuf *bufp, const char *data, int count, unsigned char **pdata){ *pdata = buf_alloc(bufp, count); memmove(*pdata, data, count); return count;}static intp9_put_user_data(struct cbuf *bufp, const char __user *data, int count, unsigned char **pdata)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -