Commit | Line | Data |
---|---|---|
b8cf945b EVH |
1 | /* |
2 | * linux/fs/9p/conv.c | |
3 | * | |
4 | * 9P protocol conversion functions | |
5 | * | |
d06a8fb1 | 6 | * Copyright (C) 2004, 2005 by Latchesar Ionkov <lucho@ionkov.net> |
b8cf945b EVH |
7 | * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> |
8 | * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov> | |
9 | * | |
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. | |
14 | * | |
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. | |
19 | * | |
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 | |
25 | * | |
26 | */ | |
27 | ||
28 | #include <linux/config.h> | |
29 | #include <linux/module.h> | |
30 | #include <linux/errno.h> | |
31 | #include <linux/fs.h> | |
32 | #include <linux/idr.h> | |
531b1094 | 33 | #include <asm/uaccess.h> |
b8cf945b EVH |
34 | #include "debug.h" |
35 | #include "v9fs.h" | |
36 | #include "9p.h" | |
37 | #include "conv.h" | |
38 | ||
39 | /* | |
40 | * Buffer to help with string parsing | |
41 | */ | |
42 | struct cbuf { | |
43 | unsigned char *sp; | |
44 | unsigned char *p; | |
45 | unsigned char *ep; | |
46 | }; | |
47 | ||
531b1094 LI |
48 | char *v9fs_str_copy(char *buf, int buflen, struct v9fs_str *str) |
49 | { | |
50 | int n; | |
51 | ||
52 | if (buflen < str->len) | |
53 | n = buflen; | |
54 | else | |
55 | n = str->len; | |
56 | ||
57 | memmove(buf, str->str, n - 1); | |
58 | ||
59 | return buf; | |
60 | } | |
61 | ||
62 | int v9fs_str_compare(char *buf, struct v9fs_str *str) | |
63 | { | |
64 | int n, ret; | |
65 | ||
66 | ret = strncmp(buf, str->str, str->len); | |
67 | ||
68 | if (!ret) { | |
69 | n = strlen(buf); | |
70 | if (n < str->len) | |
71 | ret = -1; | |
72 | else if (n > str->len) | |
73 | ret = 1; | |
74 | } | |
75 | ||
76 | return ret; | |
77 | } | |
78 | ||
b8cf945b EVH |
79 | static inline void buf_init(struct cbuf *buf, void *data, int datalen) |
80 | { | |
81 | buf->sp = buf->p = data; | |
82 | buf->ep = data + datalen; | |
83 | } | |
84 | ||
85 | static inline int buf_check_overflow(struct cbuf *buf) | |
86 | { | |
87 | return buf->p > buf->ep; | |
88 | } | |
89 | ||
d06a8fb1 | 90 | static inline int buf_check_size(struct cbuf *buf, int len) |
b8cf945b | 91 | { |
531b1094 LI |
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)); | |
95 | dump_stack(); | |
96 | buf->p = buf->ep + 1; | |
97 | return 0; | |
b8cf945b | 98 | } |
d06a8fb1 LI |
99 | |
100 | return 1; | |
b8cf945b EVH |
101 | } |
102 | ||
103 | static inline void *buf_alloc(struct cbuf *buf, int len) | |
104 | { | |
105 | void *ret = NULL; | |
106 | ||
d06a8fb1 LI |
107 | if (buf_check_size(buf, len)) { |
108 | ret = buf->p; | |
109 | buf->p += len; | |
110 | } | |
b8cf945b EVH |
111 | |
112 | return ret; | |
113 | } | |
114 | ||
115 | static inline void buf_put_int8(struct cbuf *buf, u8 val) | |
116 | { | |
d06a8fb1 LI |
117 | if (buf_check_size(buf, 1)) { |
118 | buf->p[0] = val; | |
119 | buf->p++; | |
120 | } | |
b8cf945b EVH |
121 | } |
122 | ||
123 | static inline void buf_put_int16(struct cbuf *buf, u16 val) | |
124 | { | |
d06a8fb1 LI |
125 | if (buf_check_size(buf, 2)) { |
126 | *(__le16 *) buf->p = cpu_to_le16(val); | |
127 | buf->p += 2; | |
128 | } | |
b8cf945b EVH |
129 | } |
130 | ||
131 | static inline void buf_put_int32(struct cbuf *buf, u32 val) | |
132 | { | |
d06a8fb1 LI |
133 | if (buf_check_size(buf, 4)) { |
134 | *(__le32 *)buf->p = cpu_to_le32(val); | |
135 | buf->p += 4; | |
136 | } | |
b8cf945b EVH |
137 | } |
138 | ||
139 | static inline void buf_put_int64(struct cbuf *buf, u64 val) | |
140 | { | |
d06a8fb1 LI |
141 | if (buf_check_size(buf, 8)) { |
142 | *(__le64 *)buf->p = cpu_to_le64(val); | |
143 | buf->p += 8; | |
144 | } | |
b8cf945b EVH |
145 | } |
146 | ||
147 | static inline void buf_put_stringn(struct cbuf *buf, const char *s, u16 slen) | |
148 | { | |
d06a8fb1 LI |
149 | if (buf_check_size(buf, slen + 2)) { |
150 | buf_put_int16(buf, slen); | |
151 | memcpy(buf->p, s, slen); | |
152 | buf->p += slen; | |
153 | } | |
b8cf945b EVH |
154 | } |
155 | ||
156 | static inline void buf_put_string(struct cbuf *buf, const char *s) | |
157 | { | |
158 | buf_put_stringn(buf, s, strlen(s)); | |
159 | } | |
160 | ||
b8cf945b EVH |
161 | static inline u8 buf_get_int8(struct cbuf *buf) |
162 | { | |
163 | u8 ret = 0; | |
164 | ||
d06a8fb1 LI |
165 | if (buf_check_size(buf, 1)) { |
166 | ret = buf->p[0]; | |
167 | buf->p++; | |
168 | } | |
b8cf945b EVH |
169 | |
170 | return ret; | |
171 | } | |
172 | ||
173 | static inline u16 buf_get_int16(struct cbuf *buf) | |
174 | { | |
175 | u16 ret = 0; | |
176 | ||
d06a8fb1 LI |
177 | if (buf_check_size(buf, 2)) { |
178 | ret = le16_to_cpu(*(__le16 *)buf->p); | |
179 | buf->p += 2; | |
180 | } | |
b8cf945b EVH |
181 | |
182 | return ret; | |
183 | } | |
184 | ||
185 | static inline u32 buf_get_int32(struct cbuf *buf) | |
186 | { | |
187 | u32 ret = 0; | |
188 | ||
d06a8fb1 LI |
189 | if (buf_check_size(buf, 4)) { |
190 | ret = le32_to_cpu(*(__le32 *)buf->p); | |
191 | buf->p += 4; | |
192 | } | |
b8cf945b EVH |
193 | |
194 | return ret; | |
195 | } | |
196 | ||
197 | static inline u64 buf_get_int64(struct cbuf *buf) | |
198 | { | |
199 | u64 ret = 0; | |
200 | ||
d06a8fb1 LI |
201 | if (buf_check_size(buf, 8)) { |
202 | ret = le64_to_cpu(*(__le64 *)buf->p); | |
203 | buf->p += 8; | |
204 | } | |
b8cf945b EVH |
205 | |
206 | return ret; | |
207 | } | |
208 | ||
531b1094 | 209 | static inline void buf_get_str(struct cbuf *buf, struct v9fs_str *vstr) |
b8cf945b | 210 | { |
531b1094 LI |
211 | vstr->len = buf_get_int16(buf); |
212 | if (!buf_check_overflow(buf) && buf_check_size(buf, vstr->len)) { | |
213 | vstr->str = buf->p; | |
214 | buf->p += vstr->len; | |
215 | } else { | |
216 | vstr->len = 0; | |
217 | vstr->str = NULL; | |
d06a8fb1 | 218 | } |
b8cf945b EVH |
219 | } |
220 | ||
531b1094 | 221 | static inline void buf_get_qid(struct cbuf *bufp, struct v9fs_qid *qid) |
b8cf945b | 222 | { |
531b1094 LI |
223 | qid->type = buf_get_int8(bufp); |
224 | qid->version = buf_get_int32(bufp); | |
225 | qid->path = buf_get_int64(bufp); | |
b8cf945b EVH |
226 | } |
227 | ||
228 | /** | |
531b1094 | 229 | * v9fs_size_wstat - calculate the size of a variable length stat struct |
b8cf945b | 230 | * @stat: metadata (stat) structure |
3cf6429a | 231 | * @extended: non-zero if 9P2000.u |
b8cf945b EVH |
232 | * |
233 | */ | |
234 | ||
531b1094 | 235 | static int v9fs_size_wstat(struct v9fs_wstat *wstat, int extended) |
b8cf945b EVH |
236 | { |
237 | int size = 0; | |
238 | ||
531b1094 | 239 | if (wstat == NULL) { |
b8cf945b EVH |
240 | eprintk(KERN_ERR, "v9fs_size_stat: got a NULL stat pointer\n"); |
241 | return 0; | |
242 | } | |
243 | ||
244 | size = /* 2 + *//* size[2] */ | |
245 | 2 + /* type[2] */ | |
246 | 4 + /* dev[4] */ | |
247 | 1 + /* qid.type[1] */ | |
248 | 4 + /* qid.vers[4] */ | |
249 | 8 + /* qid.path[8] */ | |
250 | 4 + /* mode[4] */ | |
251 | 4 + /* atime[4] */ | |
252 | 4 + /* mtime[4] */ | |
253 | 8 + /* length[8] */ | |
254 | 8; /* minimum sum of string lengths */ | |
255 | ||
531b1094 LI |
256 | if (wstat->name) |
257 | size += strlen(wstat->name); | |
258 | if (wstat->uid) | |
259 | size += strlen(wstat->uid); | |
260 | if (wstat->gid) | |
261 | size += strlen(wstat->gid); | |
262 | if (wstat->muid) | |
263 | size += strlen(wstat->muid); | |
b8cf945b | 264 | |
3cf6429a | 265 | if (extended) { |
b8cf945b EVH |
266 | size += 4 + /* n_uid[4] */ |
267 | 4 + /* n_gid[4] */ | |
268 | 4 + /* n_muid[4] */ | |
269 | 2; /* string length of extension[4] */ | |
531b1094 LI |
270 | if (wstat->extension) |
271 | size += strlen(wstat->extension); | |
b8cf945b EVH |
272 | } |
273 | ||
274 | return size; | |
275 | } | |
276 | ||
277 | /** | |
531b1094 | 278 | * buf_get_stat - safely decode a recieved metadata (stat) structure |
b8cf945b EVH |
279 | * @bufp: buffer to deserialize |
280 | * @stat: metadata (stat) structure | |
3cf6429a | 281 | * @extended: non-zero if 9P2000.u |
b8cf945b EVH |
282 | * |
283 | */ | |
284 | ||
531b1094 LI |
285 | static inline void |
286 | buf_get_stat(struct cbuf *bufp, struct v9fs_stat *stat, int extended) | |
b8cf945b | 287 | { |
b8cf945b EVH |
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); | |
531b1094 LI |
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); | |
b8cf945b | 302 | |
3cf6429a | 303 | if (extended) { |
531b1094 | 304 | buf_get_str(bufp, &stat->extension); |
b8cf945b EVH |
305 | stat->n_uid = buf_get_int32(bufp); |
306 | stat->n_gid = buf_get_int32(bufp); | |
307 | stat->n_muid = buf_get_int32(bufp); | |
308 | } | |
b8cf945b EVH |
309 | } |
310 | ||
311 | /** | |
312 | * v9fs_deserialize_stat - decode a received metadata structure | |
b8cf945b EVH |
313 | * @buf: buffer to deserialize |
314 | * @buflen: length of received buffer | |
315 | * @stat: metadata structure to decode into | |
3cf6429a | 316 | * @extended: non-zero if 9P2000.u |
b8cf945b | 317 | * |
531b1094 | 318 | * Note: stat will point to the buf region. |
b8cf945b EVH |
319 | */ |
320 | ||
531b1094 LI |
321 | int |
322 | v9fs_deserialize_stat(void *buf, u32 buflen, struct v9fs_stat *stat, | |
323 | int extended) | |
b8cf945b EVH |
324 | { |
325 | struct cbuf buffer; | |
326 | struct cbuf *bufp = &buffer; | |
531b1094 | 327 | unsigned char *p; |
b8cf945b EVH |
328 | |
329 | buf_init(bufp, buf, buflen); | |
531b1094 LI |
330 | p = bufp->p; |
331 | buf_get_stat(bufp, stat, extended); | |
b8cf945b | 332 | |
531b1094 | 333 | if (buf_check_overflow(bufp)) |
b8cf945b | 334 | return 0; |
531b1094 LI |
335 | else |
336 | return bufp->p - p; | |
b8cf945b EVH |
337 | } |
338 | ||
339 | /** | |
340 | * deserialize_fcall - unmarshal a response | |
b8cf945b EVH |
341 | * @buf: recieved buffer |
342 | * @buflen: length of received buffer | |
343 | * @rcall: fcall structure to populate | |
344 | * @rcalllen: length of fcall structure to populate | |
3cf6429a | 345 | * @extended: non-zero if 9P2000.u |
b8cf945b EVH |
346 | * |
347 | */ | |
348 | ||
349 | int | |
3cf6429a | 350 | v9fs_deserialize_fcall(void *buf, u32 buflen, struct v9fs_fcall *rcall, |
531b1094 | 351 | int extended) |
b8cf945b EVH |
352 | { |
353 | ||
354 | struct cbuf buffer; | |
355 | struct cbuf *bufp = &buffer; | |
b8cf945b EVH |
356 | int i = 0; |
357 | ||
358 | buf_init(bufp, buf, buflen); | |
b8cf945b | 359 | |
3cf6429a | 360 | rcall->size = buf_get_int32(bufp); |
b8cf945b EVH |
361 | rcall->id = buf_get_int8(bufp); |
362 | rcall->tag = buf_get_int16(bufp); | |
363 | ||
364 | dprintk(DEBUG_CONV, "size %d id %d tag %d\n", rcall->size, rcall->id, | |
365 | rcall->tag); | |
531b1094 | 366 | |
b8cf945b EVH |
367 | switch (rcall->id) { |
368 | default: | |
369 | eprintk(KERN_ERR, "unknown message type: %d\n", rcall->id); | |
370 | return -EPROTO; | |
371 | case RVERSION: | |
372 | rcall->params.rversion.msize = buf_get_int32(bufp); | |
531b1094 | 373 | buf_get_str(bufp, &rcall->params.rversion.version); |
b8cf945b EVH |
374 | break; |
375 | case RFLUSH: | |
376 | break; | |
377 | case RATTACH: | |
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); | |
381 | break; | |
382 | case RWALK: | |
383 | rcall->params.rwalk.nwqid = buf_get_int16(bufp); | |
531b1094 LI |
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); | |
3cf6429a LI |
387 | return -EPROTO; |
388 | } | |
389 | ||
531b1094 LI |
390 | for (i = 0; i < rcall->params.rwalk.nwqid; i++) |
391 | buf_get_qid(bufp, &rcall->params.rwalk.wqids[i]); | |
b8cf945b EVH |
392 | break; |
393 | case ROPEN: | |
531b1094 | 394 | buf_get_qid(bufp, &rcall->params.ropen.qid); |
b8cf945b EVH |
395 | rcall->params.ropen.iounit = buf_get_int32(bufp); |
396 | break; | |
397 | case RCREATE: | |
531b1094 | 398 | buf_get_qid(bufp, &rcall->params.rcreate.qid); |
b8cf945b EVH |
399 | rcall->params.rcreate.iounit = buf_get_int32(bufp); |
400 | break; | |
401 | case RREAD: | |
402 | rcall->params.rread.count = buf_get_int32(bufp); | |
531b1094 LI |
403 | rcall->params.rread.data = bufp->p; |
404 | buf_check_size(bufp, rcall->params.rread.count); | |
b8cf945b EVH |
405 | break; |
406 | case RWRITE: | |
407 | rcall->params.rwrite.count = buf_get_int32(bufp); | |
408 | break; | |
409 | case RCLUNK: | |
410 | break; | |
411 | case RREMOVE: | |
412 | break; | |
413 | case RSTAT: | |
414 | buf_get_int16(bufp); | |
531b1094 | 415 | buf_get_stat(bufp, &rcall->params.rstat.stat, extended); |
b8cf945b EVH |
416 | break; |
417 | case RWSTAT: | |
418 | break; | |
419 | case RERROR: | |
531b1094 | 420 | buf_get_str(bufp, &rcall->params.rerror.error); |
3cf6429a | 421 | if (extended) |
b8cf945b EVH |
422 | rcall->params.rerror.errno = buf_get_int16(bufp); |
423 | break; | |
424 | } | |
425 | ||
531b1094 | 426 | if (buf_check_overflow(bufp)) { |
3cf6429a | 427 | dprintk(DEBUG_ERROR, "buffer overflow\n"); |
b8cf945b | 428 | return -EIO; |
3cf6429a | 429 | } |
b8cf945b | 430 | |
531b1094 LI |
431 | return bufp->p - bufp->sp; |
432 | } | |
433 | ||
434 | static inline void v9fs_put_int8(struct cbuf *bufp, u8 val, u8 * p) | |
435 | { | |
436 | *p = val; | |
437 | buf_put_int8(bufp, val); | |
438 | } | |
439 | ||
440 | static inline void v9fs_put_int16(struct cbuf *bufp, u16 val, u16 * p) | |
441 | { | |
442 | *p = val; | |
443 | buf_put_int16(bufp, val); | |
444 | } | |
445 | ||
446 | static inline void v9fs_put_int32(struct cbuf *bufp, u32 val, u32 * p) | |
447 | { | |
448 | *p = val; | |
449 | buf_put_int32(bufp, val); | |
450 | } | |
451 | ||
452 | static inline void v9fs_put_int64(struct cbuf *bufp, u64 val, u64 * p) | |
453 | { | |
454 | *p = val; | |
455 | buf_put_int64(bufp, val); | |
456 | } | |
457 | ||
458 | static inline void | |
459 | v9fs_put_str(struct cbuf *bufp, char *data, struct v9fs_str *str) | |
460 | { | |
461 | if (data) { | |
462 | str->len = strlen(data); | |
463 | str->str = bufp->p; | |
464 | } else { | |
465 | str->len = 0; | |
466 | str->str = NULL; | |
467 | } | |
468 | ||
469 | buf_put_stringn(bufp, data, str->len); | |
470 | } | |
471 | ||
472 | static inline int | |
473 | v9fs_put_user_data(struct cbuf *bufp, const char __user * data, int count, | |
474 | unsigned char **pdata) | |
475 | { | |
476 | *pdata = buf_alloc(bufp, count); | |
477 | return copy_from_user(*pdata, data, count); | |
478 | } | |
479 | ||
480 | static void | |
481 | v9fs_put_wstat(struct cbuf *bufp, struct v9fs_wstat *wstat, | |
482 | struct v9fs_stat *stat, int statsz, int extended) | |
483 | { | |
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); | |
494 | ||
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); | |
499 | ||
500 | if (extended) { | |
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); | |
505 | } | |
506 | } | |
507 | ||
508 | static struct v9fs_fcall * | |
509 | v9fs_create_common(struct cbuf *bufp, u32 size, u8 id) | |
510 | { | |
511 | struct v9fs_fcall *fc; | |
512 | ||
513 | size += 4 + 1 + 2; /* size[4] id[1] tag[2] */ | |
514 | fc = kmalloc(sizeof(struct v9fs_fcall) + size, GFP_KERNEL); | |
515 | if (!fc) | |
516 | return ERR_PTR(-ENOMEM); | |
517 | ||
518 | fc->sdata = (char *)fc + sizeof(*fc); | |
519 | ||
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); | |
524 | ||
525 | return fc; | |
526 | } | |
527 | ||
528 | void v9fs_set_tag(struct v9fs_fcall *fc, u16 tag) | |
529 | { | |
530 | *(__le16 *) (fc->sdata + 5) = cpu_to_le16(tag); | |
531 | } | |
532 | ||
533 | struct v9fs_fcall *v9fs_create_tversion(u32 msize, char *version) | |
534 | { | |
535 | int size; | |
536 | struct v9fs_fcall *fc; | |
537 | struct cbuf buffer; | |
538 | struct cbuf *bufp = &buffer; | |
539 | ||
540 | size = 4 + 2 + strlen(version); /* msize[4] version[s] */ | |
541 | fc = v9fs_create_common(bufp, size, TVERSION); | |
542 | if (IS_ERR(fc)) | |
543 | goto error; | |
544 | ||
545 | v9fs_put_int32(bufp, msize, &fc->params.tversion.msize); | |
546 | v9fs_put_str(bufp, version, &fc->params.tversion.version); | |
547 | ||
548 | if (buf_check_overflow(bufp)) { | |
549 | kfree(fc); | |
550 | fc = ERR_PTR(-ENOMEM); | |
551 | } | |
552 | error: | |
553 | return fc; | |
554 | } | |
555 | ||
556 | struct v9fs_fcall *v9fs_create_tauth(u32 afid, char *uname, char *aname) | |
557 | { | |
558 | int size; | |
559 | struct v9fs_fcall *fc; | |
560 | struct cbuf buffer; | |
561 | struct cbuf *bufp = &buffer; | |
562 | ||
563 | size = 4 + 2 + strlen(uname) + 2 + strlen(aname); /* afid[4] uname[s] aname[s] */ | |
564 | fc = v9fs_create_common(bufp, size, TAUTH); | |
565 | if (IS_ERR(fc)) | |
566 | goto error; | |
567 | ||
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); | |
571 | ||
572 | if (buf_check_overflow(bufp)) { | |
573 | kfree(fc); | |
574 | fc = ERR_PTR(-ENOMEM); | |
575 | } | |
576 | error: | |
577 | return fc; | |
578 | } | |
579 | ||
580 | struct v9fs_fcall * | |
581 | v9fs_create_tattach(u32 fid, u32 afid, char *uname, char *aname) | |
582 | { | |
583 | int size; | |
584 | struct v9fs_fcall *fc; | |
585 | struct cbuf buffer; | |
586 | struct cbuf *bufp = &buffer; | |
587 | ||
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); | |
590 | if (IS_ERR(fc)) | |
591 | goto error; | |
592 | ||
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); | |
597 | ||
598 | error: | |
599 | return fc; | |
600 | } | |
601 | ||
602 | struct v9fs_fcall *v9fs_create_tflush(u16 oldtag) | |
603 | { | |
604 | int size; | |
605 | struct v9fs_fcall *fc; | |
606 | struct cbuf buffer; | |
607 | struct cbuf *bufp = &buffer; | |
608 | ||
609 | size = 2; /* oldtag[2] */ | |
610 | fc = v9fs_create_common(bufp, size, TFLUSH); | |
611 | if (IS_ERR(fc)) | |
612 | goto error; | |
613 | ||
614 | v9fs_put_int16(bufp, oldtag, &fc->params.tflush.oldtag); | |
615 | ||
616 | if (buf_check_overflow(bufp)) { | |
617 | kfree(fc); | |
618 | fc = ERR_PTR(-ENOMEM); | |
619 | } | |
620 | error: | |
621 | return fc; | |
622 | } | |
623 | ||
624 | struct v9fs_fcall *v9fs_create_twalk(u32 fid, u32 newfid, u16 nwname, | |
625 | char **wnames) | |
626 | { | |
627 | int i, size; | |
628 | struct v9fs_fcall *fc; | |
629 | struct cbuf buffer; | |
630 | struct cbuf *bufp = &buffer; | |
631 | ||
632 | if (nwname > V9FS_MAXWELEM) { | |
633 | dprintk(DEBUG_ERROR, "nwname > %d\n", V9FS_MAXWELEM); | |
634 | return NULL; | |
635 | } | |
636 | ||
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] */ | |
640 | } | |
641 | ||
642 | fc = v9fs_create_common(bufp, size, TWALK); | |
643 | if (IS_ERR(fc)) | |
644 | goto error; | |
645 | ||
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]); | |
651 | } | |
652 | ||
653 | if (buf_check_overflow(bufp)) { | |
654 | kfree(fc); | |
655 | fc = ERR_PTR(-ENOMEM); | |
656 | } | |
657 | error: | |
658 | return fc; | |
659 | } | |
660 | ||
661 | struct v9fs_fcall *v9fs_create_topen(u32 fid, u8 mode) | |
662 | { | |
663 | int size; | |
664 | struct v9fs_fcall *fc; | |
665 | struct cbuf buffer; | |
666 | struct cbuf *bufp = &buffer; | |
667 | ||
668 | size = 4 + 1; /* fid[4] mode[1] */ | |
669 | fc = v9fs_create_common(bufp, size, TOPEN); | |
670 | if (IS_ERR(fc)) | |
671 | goto error; | |
672 | ||
673 | v9fs_put_int32(bufp, fid, &fc->params.topen.fid); | |
674 | v9fs_put_int8(bufp, mode, &fc->params.topen.mode); | |
675 | ||
676 | if (buf_check_overflow(bufp)) { | |
677 | kfree(fc); | |
678 | fc = ERR_PTR(-ENOMEM); | |
679 | } | |
680 | error: | |
681 | return fc; | |
682 | } | |
683 | ||
684 | struct v9fs_fcall *v9fs_create_tcreate(u32 fid, char *name, u32 perm, u8 mode) | |
685 | { | |
686 | int size; | |
687 | struct v9fs_fcall *fc; | |
688 | struct cbuf buffer; | |
689 | struct cbuf *bufp = &buffer; | |
690 | ||
691 | size = 4 + 2 + strlen(name) + 4 + 1; /* fid[4] name[s] perm[4] mode[1] */ | |
692 | fc = v9fs_create_common(bufp, size, TCREATE); | |
693 | if (IS_ERR(fc)) | |
694 | goto error; | |
695 | ||
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); | |
700 | ||
701 | if (buf_check_overflow(bufp)) { | |
702 | kfree(fc); | |
703 | fc = ERR_PTR(-ENOMEM); | |
704 | } | |
705 | error: | |
706 | return fc; | |
707 | } | |
708 | ||
709 | struct v9fs_fcall *v9fs_create_tread(u32 fid, u64 offset, u32 count) | |
710 | { | |
711 | int size; | |
712 | struct v9fs_fcall *fc; | |
713 | struct cbuf buffer; | |
714 | struct cbuf *bufp = &buffer; | |
715 | ||
716 | size = 4 + 8 + 4; /* fid[4] offset[8] count[4] */ | |
717 | fc = v9fs_create_common(bufp, size, TREAD); | |
718 | if (IS_ERR(fc)) | |
719 | goto error; | |
720 | ||
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); | |
724 | ||
725 | if (buf_check_overflow(bufp)) { | |
726 | kfree(fc); | |
727 | fc = ERR_PTR(-ENOMEM); | |
728 | } | |
729 | error: | |
730 | return fc; | |
731 | } | |
732 | ||
733 | struct v9fs_fcall *v9fs_create_twrite(u32 fid, u64 offset, u32 count, | |
734 | const char __user * data) | |
735 | { | |
736 | int size, err; | |
737 | struct v9fs_fcall *fc; | |
738 | struct cbuf buffer; | |
739 | struct cbuf *bufp = &buffer; | |
740 | ||
741 | size = 4 + 8 + 4 + count; /* fid[4] offset[8] count[4] data[count] */ | |
742 | fc = v9fs_create_common(bufp, size, TWRITE); | |
743 | if (IS_ERR(fc)) | |
744 | goto error; | |
745 | ||
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); | |
750 | if (err) { | |
751 | kfree(fc); | |
752 | fc = ERR_PTR(err); | |
753 | } | |
754 | ||
755 | if (buf_check_overflow(bufp)) { | |
756 | kfree(fc); | |
757 | fc = ERR_PTR(-ENOMEM); | |
758 | } | |
759 | error: | |
760 | return fc; | |
761 | } | |
762 | ||
763 | struct v9fs_fcall *v9fs_create_tclunk(u32 fid) | |
764 | { | |
765 | int size; | |
766 | struct v9fs_fcall *fc; | |
767 | struct cbuf buffer; | |
768 | struct cbuf *bufp = &buffer; | |
769 | ||
770 | size = 4; /* fid[4] */ | |
771 | fc = v9fs_create_common(bufp, size, TCLUNK); | |
772 | if (IS_ERR(fc)) | |
773 | goto error; | |
774 | ||
775 | v9fs_put_int32(bufp, fid, &fc->params.tclunk.fid); | |
776 | ||
777 | if (buf_check_overflow(bufp)) { | |
778 | kfree(fc); | |
779 | fc = ERR_PTR(-ENOMEM); | |
780 | } | |
781 | error: | |
782 | return fc; | |
783 | } | |
784 | ||
785 | struct v9fs_fcall *v9fs_create_tremove(u32 fid) | |
786 | { | |
787 | int size; | |
788 | struct v9fs_fcall *fc; | |
789 | struct cbuf buffer; | |
790 | struct cbuf *bufp = &buffer; | |
791 | ||
792 | size = 4; /* fid[4] */ | |
793 | fc = v9fs_create_common(bufp, size, TREMOVE); | |
794 | if (IS_ERR(fc)) | |
795 | goto error; | |
796 | ||
797 | v9fs_put_int32(bufp, fid, &fc->params.tremove.fid); | |
798 | ||
799 | if (buf_check_overflow(bufp)) { | |
800 | kfree(fc); | |
801 | fc = ERR_PTR(-ENOMEM); | |
802 | } | |
803 | error: | |
804 | return fc; | |
805 | } | |
806 | ||
807 | struct v9fs_fcall *v9fs_create_tstat(u32 fid) | |
808 | { | |
809 | int size; | |
810 | struct v9fs_fcall *fc; | |
811 | struct cbuf buffer; | |
812 | struct cbuf *bufp = &buffer; | |
813 | ||
814 | size = 4; /* fid[4] */ | |
815 | fc = v9fs_create_common(bufp, size, TSTAT); | |
816 | if (IS_ERR(fc)) | |
817 | goto error; | |
818 | ||
819 | v9fs_put_int32(bufp, fid, &fc->params.tstat.fid); | |
820 | ||
821 | if (buf_check_overflow(bufp)) { | |
822 | kfree(fc); | |
823 | fc = ERR_PTR(-ENOMEM); | |
824 | } | |
825 | error: | |
826 | return fc; | |
827 | } | |
828 | ||
829 | struct v9fs_fcall *v9fs_create_twstat(u32 fid, struct v9fs_wstat *wstat, | |
830 | int extended) | |
831 | { | |
832 | int size, statsz; | |
833 | struct v9fs_fcall *fc; | |
834 | struct cbuf buffer; | |
835 | struct cbuf *bufp = &buffer; | |
836 | ||
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); | |
840 | if (IS_ERR(fc)) | |
841 | goto error; | |
842 | ||
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); | |
846 | ||
847 | if (buf_check_overflow(bufp)) { | |
848 | kfree(fc); | |
849 | fc = ERR_PTR(-ENOMEM); | |
850 | } | |
851 | error: | |
852 | return fc; | |
b8cf945b | 853 | } |