4 * 9P protocol conversion functions
6 * Copyright (C) 2004, 2005 by Latchesar Ionkov <lucho@ionkov.net>
7 * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
8 * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to:
22 * Free Software Foundation
23 * 51 Franklin Street, Fifth Floor
24 * Boston, MA 02111-1301 USA
28 #include <linux/config.h>
29 #include <linux/module.h>
30 #include <linux/errno.h>
32 #include <linux/idr.h>
33 #include <asm/uaccess.h>
40 * Buffer to help with string parsing
48 char *v9fs_str_copy(char *buf, int buflen, struct v9fs_str *str)
52 if (buflen < str->len)
57 memmove(buf, str->str, n - 1);
62 int v9fs_str_compare(char *buf, struct v9fs_str *str)
66 ret = strncmp(buf, str->str, str->len);
72 else if (n > str->len)
79 static inline void buf_init(struct cbuf *buf, void *data, int datalen)
81 buf->sp = buf->p = data;
82 buf->ep = data + datalen;
85 static inline int buf_check_overflow(struct cbuf *buf)
87 return buf->p > buf->ep;
90 static inline int buf_check_size(struct cbuf *buf, int len)
92 if (buf->p + len > buf->ep && buf->p < buf->ep) {
93 eprintk(KERN_ERR, "buffer overflow: want %d has %d\n",
94 len, (int)(buf->ep - buf->p));
103 static inline void *buf_alloc(struct cbuf *buf, int len)
107 if (buf_check_size(buf, len)) {
115 static inline void buf_put_int8(struct cbuf *buf, u8 val)
117 if (buf_check_size(buf, 1)) {
123 static inline void buf_put_int16(struct cbuf *buf, u16 val)
125 if (buf_check_size(buf, 2)) {
126 *(__le16 *) buf->p = cpu_to_le16(val);
131 static inline void buf_put_int32(struct cbuf *buf, u32 val)
133 if (buf_check_size(buf, 4)) {
134 *(__le32 *)buf->p = cpu_to_le32(val);
139 static inline void buf_put_int64(struct cbuf *buf, u64 val)
141 if (buf_check_size(buf, 8)) {
142 *(__le64 *)buf->p = cpu_to_le64(val);
147 static inline void buf_put_stringn(struct cbuf *buf, const char *s, u16 slen)
149 if (buf_check_size(buf, slen + 2)) {
150 buf_put_int16(buf, slen);
151 memcpy(buf->p, s, slen);
156 static inline void buf_put_string(struct cbuf *buf, const char *s)
158 buf_put_stringn(buf, s, strlen(s));
161 static inline u8 buf_get_int8(struct cbuf *buf)
165 if (buf_check_size(buf, 1)) {
173 static inline u16 buf_get_int16(struct cbuf *buf)
177 if (buf_check_size(buf, 2)) {
178 ret = le16_to_cpu(*(__le16 *)buf->p);
185 static inline u32 buf_get_int32(struct cbuf *buf)
189 if (buf_check_size(buf, 4)) {
190 ret = le32_to_cpu(*(__le32 *)buf->p);
197 static inline u64 buf_get_int64(struct cbuf *buf)
201 if (buf_check_size(buf, 8)) {
202 ret = le64_to_cpu(*(__le64 *)buf->p);
209 static inline void buf_get_str(struct cbuf *buf, struct v9fs_str *vstr)
211 vstr->len = buf_get_int16(buf);
212 if (!buf_check_overflow(buf) && buf_check_size(buf, vstr->len)) {
221 static inline void buf_get_qid(struct cbuf *bufp, struct v9fs_qid *qid)
223 qid->type = buf_get_int8(bufp);
224 qid->version = buf_get_int32(bufp);
225 qid->path = buf_get_int64(bufp);
229 * v9fs_size_wstat - calculate the size of a variable length stat struct
230 * @stat: metadata (stat) structure
231 * @extended: non-zero if 9P2000.u
235 static int v9fs_size_wstat(struct v9fs_wstat *wstat, int extended)
240 eprintk(KERN_ERR, "v9fs_size_stat: got a NULL stat pointer\n");
244 size = /* 2 + *//* size[2] */
247 1 + /* qid.type[1] */
248 4 + /* qid.vers[4] */
249 8 + /* qid.path[8] */
254 8; /* minimum sum of string lengths */
257 size += strlen(wstat->name);
259 size += strlen(wstat->uid);
261 size += strlen(wstat->gid);
263 size += strlen(wstat->muid);
266 size += 4 + /* n_uid[4] */
269 2; /* string length of extension[4] */
270 if (wstat->extension)
271 size += strlen(wstat->extension);
278 * buf_get_stat - safely decode a recieved metadata (stat) structure
279 * @bufp: buffer to deserialize
280 * @stat: metadata (stat) structure
281 * @extended: non-zero if 9P2000.u
286 buf_get_stat(struct cbuf *bufp, struct v9fs_stat *stat, int extended)
288 stat->size = buf_get_int16(bufp);
289 stat->type = buf_get_int16(bufp);
290 stat->dev = buf_get_int32(bufp);
291 stat->qid.type = buf_get_int8(bufp);
292 stat->qid.version = buf_get_int32(bufp);
293 stat->qid.path = buf_get_int64(bufp);
294 stat->mode = buf_get_int32(bufp);
295 stat->atime = buf_get_int32(bufp);
296 stat->mtime = buf_get_int32(bufp);
297 stat->length = buf_get_int64(bufp);
298 buf_get_str(bufp, &stat->name);
299 buf_get_str(bufp, &stat->uid);
300 buf_get_str(bufp, &stat->gid);
301 buf_get_str(bufp, &stat->muid);
304 buf_get_str(bufp, &stat->extension);
305 stat->n_uid = buf_get_int32(bufp);
306 stat->n_gid = buf_get_int32(bufp);
307 stat->n_muid = buf_get_int32(bufp);
312 * v9fs_deserialize_stat - decode a received metadata structure
313 * @buf: buffer to deserialize
314 * @buflen: length of received buffer
315 * @stat: metadata structure to decode into
316 * @extended: non-zero if 9P2000.u
318 * Note: stat will point to the buf region.
322 v9fs_deserialize_stat(void *buf, u32 buflen, struct v9fs_stat *stat,
326 struct cbuf *bufp = &buffer;
329 buf_init(bufp, buf, buflen);
331 buf_get_stat(bufp, stat, extended);
333 if (buf_check_overflow(bufp))
340 * deserialize_fcall - unmarshal a response
341 * @buf: recieved buffer
342 * @buflen: length of received buffer
343 * @rcall: fcall structure to populate
344 * @rcalllen: length of fcall structure to populate
345 * @extended: non-zero if 9P2000.u
350 v9fs_deserialize_fcall(void *buf, u32 buflen, struct v9fs_fcall *rcall,
355 struct cbuf *bufp = &buffer;
358 buf_init(bufp, buf, buflen);
360 rcall->size = buf_get_int32(bufp);
361 rcall->id = buf_get_int8(bufp);
362 rcall->tag = buf_get_int16(bufp);
364 dprintk(DEBUG_CONV, "size %d id %d tag %d\n", rcall->size, rcall->id,
369 eprintk(KERN_ERR, "unknown message type: %d\n", rcall->id);
372 rcall->params.rversion.msize = buf_get_int32(bufp);
373 buf_get_str(bufp, &rcall->params.rversion.version);
378 rcall->params.rattach.qid.type = buf_get_int8(bufp);
379 rcall->params.rattach.qid.version = buf_get_int32(bufp);
380 rcall->params.rattach.qid.path = buf_get_int64(bufp);
383 rcall->params.rwalk.nwqid = buf_get_int16(bufp);
384 if (rcall->params.rwalk.nwqid > V9FS_MAXWELEM) {
385 eprintk(KERN_ERR, "Rwalk with more than %d qids: %d\n",
386 V9FS_MAXWELEM, rcall->params.rwalk.nwqid);
390 for (i = 0; i < rcall->params.rwalk.nwqid; i++)
391 buf_get_qid(bufp, &rcall->params.rwalk.wqids[i]);
394 buf_get_qid(bufp, &rcall->params.ropen.qid);
395 rcall->params.ropen.iounit = buf_get_int32(bufp);
398 buf_get_qid(bufp, &rcall->params.rcreate.qid);
399 rcall->params.rcreate.iounit = buf_get_int32(bufp);
402 rcall->params.rread.count = buf_get_int32(bufp);
403 rcall->params.rread.data = bufp->p;
404 buf_check_size(bufp, rcall->params.rread.count);
407 rcall->params.rwrite.count = buf_get_int32(bufp);
415 buf_get_stat(bufp, &rcall->params.rstat.stat, extended);
420 buf_get_str(bufp, &rcall->params.rerror.error);
422 rcall->params.rerror.errno = buf_get_int16(bufp);
426 if (buf_check_overflow(bufp)) {
427 dprintk(DEBUG_ERROR, "buffer overflow\n");
431 return bufp->p - bufp->sp;
434 static inline void v9fs_put_int8(struct cbuf *bufp, u8 val, u8 * p)
437 buf_put_int8(bufp, val);
440 static inline void v9fs_put_int16(struct cbuf *bufp, u16 val, u16 * p)
443 buf_put_int16(bufp, val);
446 static inline void v9fs_put_int32(struct cbuf *bufp, u32 val, u32 * p)
449 buf_put_int32(bufp, val);
452 static inline void v9fs_put_int64(struct cbuf *bufp, u64 val, u64 * p)
455 buf_put_int64(bufp, val);
459 v9fs_put_str(struct cbuf *bufp, char *data, struct v9fs_str *str)
462 str->len = strlen(data);
469 buf_put_stringn(bufp, data, str->len);
473 v9fs_put_user_data(struct cbuf *bufp, const char __user * data, int count,
474 unsigned char **pdata)
476 *pdata = buf_alloc(bufp, count);
477 return copy_from_user(*pdata, data, count);
481 v9fs_put_wstat(struct cbuf *bufp, struct v9fs_wstat *wstat,
482 struct v9fs_stat *stat, int statsz, int extended)
484 v9fs_put_int16(bufp, statsz, &stat->size);
485 v9fs_put_int16(bufp, wstat->type, &stat->type);
486 v9fs_put_int32(bufp, wstat->dev, &stat->dev);
487 v9fs_put_int8(bufp, wstat->qid.type, &stat->qid.type);
488 v9fs_put_int32(bufp, wstat->qid.version, &stat->qid.version);
489 v9fs_put_int64(bufp, wstat->qid.path, &stat->qid.path);
490 v9fs_put_int32(bufp, wstat->mode, &stat->mode);
491 v9fs_put_int32(bufp, wstat->atime, &stat->atime);
492 v9fs_put_int32(bufp, wstat->mtime, &stat->mtime);
493 v9fs_put_int64(bufp, wstat->length, &stat->length);
495 v9fs_put_str(bufp, wstat->name, &stat->name);
496 v9fs_put_str(bufp, wstat->uid, &stat->uid);
497 v9fs_put_str(bufp, wstat->gid, &stat->gid);
498 v9fs_put_str(bufp, wstat->muid, &stat->muid);
501 v9fs_put_str(bufp, wstat->extension, &stat->extension);
502 v9fs_put_int32(bufp, wstat->n_uid, &stat->n_uid);
503 v9fs_put_int32(bufp, wstat->n_gid, &stat->n_gid);
504 v9fs_put_int32(bufp, wstat->n_muid, &stat->n_muid);
508 static struct v9fs_fcall *
509 v9fs_create_common(struct cbuf *bufp, u32 size, u8 id)
511 struct v9fs_fcall *fc;
513 size += 4 + 1 + 2; /* size[4] id[1] tag[2] */
514 fc = kmalloc(sizeof(struct v9fs_fcall) + size, GFP_KERNEL);
516 return ERR_PTR(-ENOMEM);
518 fc->sdata = (char *)fc + sizeof(*fc);
520 buf_init(bufp, (char *)fc->sdata, size);
521 v9fs_put_int32(bufp, size, &fc->size);
522 v9fs_put_int8(bufp, id, &fc->id);
523 v9fs_put_int16(bufp, V9FS_NOTAG, &fc->tag);
528 void v9fs_set_tag(struct v9fs_fcall *fc, u16 tag)
530 *(__le16 *) (fc->sdata + 5) = cpu_to_le16(tag);
533 struct v9fs_fcall *v9fs_create_tversion(u32 msize, char *version)
536 struct v9fs_fcall *fc;
538 struct cbuf *bufp = &buffer;
540 size = 4 + 2 + strlen(version); /* msize[4] version[s] */
541 fc = v9fs_create_common(bufp, size, TVERSION);
545 v9fs_put_int32(bufp, msize, &fc->params.tversion.msize);
546 v9fs_put_str(bufp, version, &fc->params.tversion.version);
548 if (buf_check_overflow(bufp)) {
550 fc = ERR_PTR(-ENOMEM);
556 struct v9fs_fcall *v9fs_create_tauth(u32 afid, char *uname, char *aname)
559 struct v9fs_fcall *fc;
561 struct cbuf *bufp = &buffer;
563 size = 4 + 2 + strlen(uname) + 2 + strlen(aname); /* afid[4] uname[s] aname[s] */
564 fc = v9fs_create_common(bufp, size, TAUTH);
568 v9fs_put_int32(bufp, afid, &fc->params.tauth.afid);
569 v9fs_put_str(bufp, uname, &fc->params.tauth.uname);
570 v9fs_put_str(bufp, aname, &fc->params.tauth.aname);
572 if (buf_check_overflow(bufp)) {
574 fc = ERR_PTR(-ENOMEM);
581 v9fs_create_tattach(u32 fid, u32 afid, char *uname, char *aname)
584 struct v9fs_fcall *fc;
586 struct cbuf *bufp = &buffer;
588 size = 4 + 4 + 2 + strlen(uname) + 2 + strlen(aname); /* fid[4] afid[4] uname[s] aname[s] */
589 fc = v9fs_create_common(bufp, size, TATTACH);
593 v9fs_put_int32(bufp, fid, &fc->params.tattach.fid);
594 v9fs_put_int32(bufp, afid, &fc->params.tattach.afid);
595 v9fs_put_str(bufp, uname, &fc->params.tattach.uname);
596 v9fs_put_str(bufp, aname, &fc->params.tattach.aname);
602 struct v9fs_fcall *v9fs_create_tflush(u16 oldtag)
605 struct v9fs_fcall *fc;
607 struct cbuf *bufp = &buffer;
609 size = 2; /* oldtag[2] */
610 fc = v9fs_create_common(bufp, size, TFLUSH);
614 v9fs_put_int16(bufp, oldtag, &fc->params.tflush.oldtag);
616 if (buf_check_overflow(bufp)) {
618 fc = ERR_PTR(-ENOMEM);
624 struct v9fs_fcall *v9fs_create_twalk(u32 fid, u32 newfid, u16 nwname,
628 struct v9fs_fcall *fc;
630 struct cbuf *bufp = &buffer;
632 if (nwname > V9FS_MAXWELEM) {
633 dprintk(DEBUG_ERROR, "nwname > %d\n", V9FS_MAXWELEM);
637 size = 4 + 4 + 2; /* fid[4] newfid[4] nwname[2] ... */
638 for (i = 0; i < nwname; i++) {
639 size += 2 + strlen(wnames[i]); /* wname[s] */
642 fc = v9fs_create_common(bufp, size, TWALK);
646 v9fs_put_int32(bufp, fid, &fc->params.twalk.fid);
647 v9fs_put_int32(bufp, newfid, &fc->params.twalk.newfid);
648 v9fs_put_int16(bufp, nwname, &fc->params.twalk.nwname);
649 for (i = 0; i < nwname; i++) {
650 v9fs_put_str(bufp, wnames[i], &fc->params.twalk.wnames[i]);
653 if (buf_check_overflow(bufp)) {
655 fc = ERR_PTR(-ENOMEM);
661 struct v9fs_fcall *v9fs_create_topen(u32 fid, u8 mode)
664 struct v9fs_fcall *fc;
666 struct cbuf *bufp = &buffer;
668 size = 4 + 1; /* fid[4] mode[1] */
669 fc = v9fs_create_common(bufp, size, TOPEN);
673 v9fs_put_int32(bufp, fid, &fc->params.topen.fid);
674 v9fs_put_int8(bufp, mode, &fc->params.topen.mode);
676 if (buf_check_overflow(bufp)) {
678 fc = ERR_PTR(-ENOMEM);
684 struct v9fs_fcall *v9fs_create_tcreate(u32 fid, char *name, u32 perm, u8 mode)
687 struct v9fs_fcall *fc;
689 struct cbuf *bufp = &buffer;
691 size = 4 + 2 + strlen(name) + 4 + 1; /* fid[4] name[s] perm[4] mode[1] */
692 fc = v9fs_create_common(bufp, size, TCREATE);
696 v9fs_put_int32(bufp, fid, &fc->params.tcreate.fid);
697 v9fs_put_str(bufp, name, &fc->params.tcreate.name);
698 v9fs_put_int32(bufp, perm, &fc->params.tcreate.perm);
699 v9fs_put_int8(bufp, mode, &fc->params.tcreate.mode);
701 if (buf_check_overflow(bufp)) {
703 fc = ERR_PTR(-ENOMEM);
709 struct v9fs_fcall *v9fs_create_tread(u32 fid, u64 offset, u32 count)
712 struct v9fs_fcall *fc;
714 struct cbuf *bufp = &buffer;
716 size = 4 + 8 + 4; /* fid[4] offset[8] count[4] */
717 fc = v9fs_create_common(bufp, size, TREAD);
721 v9fs_put_int32(bufp, fid, &fc->params.tread.fid);
722 v9fs_put_int64(bufp, offset, &fc->params.tread.offset);
723 v9fs_put_int32(bufp, count, &fc->params.tread.count);
725 if (buf_check_overflow(bufp)) {
727 fc = ERR_PTR(-ENOMEM);
733 struct v9fs_fcall *v9fs_create_twrite(u32 fid, u64 offset, u32 count,
734 const char __user * data)
737 struct v9fs_fcall *fc;
739 struct cbuf *bufp = &buffer;
741 size = 4 + 8 + 4 + count; /* fid[4] offset[8] count[4] data[count] */
742 fc = v9fs_create_common(bufp, size, TWRITE);
746 v9fs_put_int32(bufp, fid, &fc->params.twrite.fid);
747 v9fs_put_int64(bufp, offset, &fc->params.twrite.offset);
748 v9fs_put_int32(bufp, count, &fc->params.twrite.count);
749 err = v9fs_put_user_data(bufp, data, count, &fc->params.twrite.data);
755 if (buf_check_overflow(bufp)) {
757 fc = ERR_PTR(-ENOMEM);
763 struct v9fs_fcall *v9fs_create_tclunk(u32 fid)
766 struct v9fs_fcall *fc;
768 struct cbuf *bufp = &buffer;
770 size = 4; /* fid[4] */
771 fc = v9fs_create_common(bufp, size, TCLUNK);
775 v9fs_put_int32(bufp, fid, &fc->params.tclunk.fid);
777 if (buf_check_overflow(bufp)) {
779 fc = ERR_PTR(-ENOMEM);
785 struct v9fs_fcall *v9fs_create_tremove(u32 fid)
788 struct v9fs_fcall *fc;
790 struct cbuf *bufp = &buffer;
792 size = 4; /* fid[4] */
793 fc = v9fs_create_common(bufp, size, TREMOVE);
797 v9fs_put_int32(bufp, fid, &fc->params.tremove.fid);
799 if (buf_check_overflow(bufp)) {
801 fc = ERR_PTR(-ENOMEM);
807 struct v9fs_fcall *v9fs_create_tstat(u32 fid)
810 struct v9fs_fcall *fc;
812 struct cbuf *bufp = &buffer;
814 size = 4; /* fid[4] */
815 fc = v9fs_create_common(bufp, size, TSTAT);
819 v9fs_put_int32(bufp, fid, &fc->params.tstat.fid);
821 if (buf_check_overflow(bufp)) {
823 fc = ERR_PTR(-ENOMEM);
829 struct v9fs_fcall *v9fs_create_twstat(u32 fid, struct v9fs_wstat *wstat,
833 struct v9fs_fcall *fc;
835 struct cbuf *bufp = &buffer;
837 statsz = v9fs_size_wstat(wstat, extended);
838 size = 4 + 2 + 2 + statsz; /* fid[4] stat[n] */
839 fc = v9fs_create_common(bufp, size, TWSTAT);
843 v9fs_put_int32(bufp, fid, &fc->params.twstat.fid);
844 buf_put_int16(bufp, statsz + 2);
845 v9fs_put_wstat(bufp, wstat, &fc->params.twstat.stat, statsz, extended);
847 if (buf_check_overflow(bufp)) {
849 fc = ERR_PTR(-ENOMEM);