diff options
| author | Anton Altaparmakov <aia21@cantab.net> | 2006-01-19 11:39:33 -0500 |
|---|---|---|
| committer | Anton Altaparmakov <aia21@cantab.net> | 2006-01-19 11:39:33 -0500 |
| commit | 944d79559d154c12becde0dab327016cf438f46c (patch) | |
| tree | 50c101806f4d3b6585222dda060559eb4f3e005a /fs/9p/conv.c | |
| parent | d087e4bdd24ebe3ae3d0b265b6573ec901af4b4b (diff) | |
| parent | 0f36b018b2e314d45af86449f1a97facb1fbe300 (diff) | |
Merge branch 'master' of /usr/src/ntfs-2.6/
Diffstat (limited to 'fs/9p/conv.c')
| -rw-r--r-- | fs/9p/conv.c | 906 |
1 files changed, 512 insertions, 394 deletions
diff --git a/fs/9p/conv.c b/fs/9p/conv.c index 18121af99d3e..32a9f99154e2 100644 --- a/fs/9p/conv.c +++ b/fs/9p/conv.c | |||
| @@ -30,7 +30,7 @@ | |||
| 30 | #include <linux/errno.h> | 30 | #include <linux/errno.h> |
| 31 | #include <linux/fs.h> | 31 | #include <linux/fs.h> |
| 32 | #include <linux/idr.h> | 32 | #include <linux/idr.h> |
| 33 | 33 | #include <asm/uaccess.h> | |
| 34 | #include "debug.h" | 34 | #include "debug.h" |
| 35 | #include "v9fs.h" | 35 | #include "v9fs.h" |
| 36 | #include "9p.h" | 36 | #include "9p.h" |
| @@ -56,20 +56,23 @@ static inline int buf_check_overflow(struct cbuf *buf) | |||
| 56 | return buf->p > buf->ep; | 56 | return buf->p > buf->ep; |
| 57 | } | 57 | } |
| 58 | 58 | ||
| 59 | static inline int buf_check_size(struct cbuf *buf, int len) | 59 | static int buf_check_size(struct cbuf *buf, int len) |
| 60 | { | 60 | { |
| 61 | if (buf->p+len > buf->ep) { | 61 | if (buf->p + len > buf->ep) { |
| 62 | if (buf->p < buf->ep) { | 62 | if (buf->p < buf->ep) { |
| 63 | eprintk(KERN_ERR, "buffer overflow\n"); | 63 | eprintk(KERN_ERR, "buffer overflow: want %d has %d\n", |
| 64 | len, (int)(buf->ep - buf->p)); | ||
| 65 | dump_stack(); | ||
| 64 | buf->p = buf->ep + 1; | 66 | buf->p = buf->ep + 1; |
| 65 | return 0; | ||
| 66 | } | 67 | } |
| 68 | |||
| 69 | return 0; | ||
| 67 | } | 70 | } |
| 68 | 71 | ||
| 69 | return 1; | 72 | return 1; |
| 70 | } | 73 | } |
| 71 | 74 | ||
| 72 | static inline void *buf_alloc(struct cbuf *buf, int len) | 75 | static void *buf_alloc(struct cbuf *buf, int len) |
| 73 | { | 76 | { |
| 74 | void *ret = NULL; | 77 | void *ret = NULL; |
| 75 | 78 | ||
| @@ -81,7 +84,7 @@ static inline void *buf_alloc(struct cbuf *buf, int len) | |||
| 81 | return ret; | 84 | return ret; |
| 82 | } | 85 | } |
| 83 | 86 | ||
| 84 | static inline void buf_put_int8(struct cbuf *buf, u8 val) | 87 | static void buf_put_int8(struct cbuf *buf, u8 val) |
| 85 | { | 88 | { |
| 86 | if (buf_check_size(buf, 1)) { | 89 | if (buf_check_size(buf, 1)) { |
| 87 | buf->p[0] = val; | 90 | buf->p[0] = val; |
| @@ -89,7 +92,7 @@ static inline void buf_put_int8(struct cbuf *buf, u8 val) | |||
| 89 | } | 92 | } |
| 90 | } | 93 | } |
| 91 | 94 | ||
| 92 | static inline void buf_put_int16(struct cbuf *buf, u16 val) | 95 | static void buf_put_int16(struct cbuf *buf, u16 val) |
| 93 | { | 96 | { |
| 94 | if (buf_check_size(buf, 2)) { | 97 | if (buf_check_size(buf, 2)) { |
| 95 | *(__le16 *) buf->p = cpu_to_le16(val); | 98 | *(__le16 *) buf->p = cpu_to_le16(val); |
| @@ -97,7 +100,7 @@ static inline void buf_put_int16(struct cbuf *buf, u16 val) | |||
| 97 | } | 100 | } |
| 98 | } | 101 | } |
| 99 | 102 | ||
| 100 | static inline void buf_put_int32(struct cbuf *buf, u32 val) | 103 | static void buf_put_int32(struct cbuf *buf, u32 val) |
| 101 | { | 104 | { |
| 102 | if (buf_check_size(buf, 4)) { | 105 | if (buf_check_size(buf, 4)) { |
| 103 | *(__le32 *)buf->p = cpu_to_le32(val); | 106 | *(__le32 *)buf->p = cpu_to_le32(val); |
| @@ -105,7 +108,7 @@ static inline void buf_put_int32(struct cbuf *buf, u32 val) | |||
| 105 | } | 108 | } |
| 106 | } | 109 | } |
| 107 | 110 | ||
| 108 | static inline void buf_put_int64(struct cbuf *buf, u64 val) | 111 | static void buf_put_int64(struct cbuf *buf, u64 val) |
| 109 | { | 112 | { |
| 110 | if (buf_check_size(buf, 8)) { | 113 | if (buf_check_size(buf, 8)) { |
| 111 | *(__le64 *)buf->p = cpu_to_le64(val); | 114 | *(__le64 *)buf->p = cpu_to_le64(val); |
| @@ -113,7 +116,7 @@ static inline void buf_put_int64(struct cbuf *buf, u64 val) | |||
| 113 | } | 116 | } |
| 114 | } | 117 | } |
| 115 | 118 | ||
| 116 | static inline void buf_put_stringn(struct cbuf *buf, const char *s, u16 slen) | 119 | static void buf_put_stringn(struct cbuf *buf, const char *s, u16 slen) |
| 117 | { | 120 | { |
| 118 | if (buf_check_size(buf, slen + 2)) { | 121 | if (buf_check_size(buf, slen + 2)) { |
| 119 | buf_put_int16(buf, slen); | 122 | buf_put_int16(buf, slen); |
| @@ -127,15 +130,7 @@ static inline void buf_put_string(struct cbuf *buf, const char *s) | |||
| 127 | buf_put_stringn(buf, s, strlen(s)); | 130 | buf_put_stringn(buf, s, strlen(s)); |
| 128 | } | 131 | } |
| 129 | 132 | ||
| 130 | static inline void buf_put_data(struct cbuf *buf, void *data, u32 datalen) | 133 | static u8 buf_get_int8(struct cbuf *buf) |
| 131 | { | ||
| 132 | if (buf_check_size(buf, datalen)) { | ||
| 133 | memcpy(buf->p, data, datalen); | ||
| 134 | buf->p += datalen; | ||
| 135 | } | ||
| 136 | } | ||
| 137 | |||
| 138 | static inline u8 buf_get_int8(struct cbuf *buf) | ||
| 139 | { | 134 | { |
| 140 | u8 ret = 0; | 135 | u8 ret = 0; |
| 141 | 136 | ||
| @@ -147,7 +142,7 @@ static inline u8 buf_get_int8(struct cbuf *buf) | |||
| 147 | return ret; | 142 | return ret; |
| 148 | } | 143 | } |
| 149 | 144 | ||
| 150 | static inline u16 buf_get_int16(struct cbuf *buf) | 145 | static u16 buf_get_int16(struct cbuf *buf) |
| 151 | { | 146 | { |
| 152 | u16 ret = 0; | 147 | u16 ret = 0; |
| 153 | 148 | ||
| @@ -159,7 +154,7 @@ static inline u16 buf_get_int16(struct cbuf *buf) | |||
| 159 | return ret; | 154 | return ret; |
| 160 | } | 155 | } |
| 161 | 156 | ||
| 162 | static inline u32 buf_get_int32(struct cbuf *buf) | 157 | static u32 buf_get_int32(struct cbuf *buf) |
| 163 | { | 158 | { |
| 164 | u32 ret = 0; | 159 | u32 ret = 0; |
| 165 | 160 | ||
| @@ -171,7 +166,7 @@ static inline u32 buf_get_int32(struct cbuf *buf) | |||
| 171 | return ret; | 166 | return ret; |
| 172 | } | 167 | } |
| 173 | 168 | ||
| 174 | static inline u64 buf_get_int64(struct cbuf *buf) | 169 | static u64 buf_get_int64(struct cbuf *buf) |
| 175 | { | 170 | { |
| 176 | u64 ret = 0; | 171 | u64 ret = 0; |
| 177 | 172 | ||
| @@ -183,86 +178,37 @@ static inline u64 buf_get_int64(struct cbuf *buf) | |||
| 183 | return ret; | 178 | return ret; |
| 184 | } | 179 | } |
| 185 | 180 | ||
| 186 | static inline int | 181 | static void buf_get_str(struct cbuf *buf, struct v9fs_str *vstr) |
| 187 | buf_get_string(struct cbuf *buf, char *data, unsigned int datalen) | ||
| 188 | { | ||
| 189 | u16 len = 0; | ||
| 190 | |||
| 191 | len = buf_get_int16(buf); | ||
| 192 | if (!buf_check_overflow(buf) && buf_check_size(buf, len) && len+1>datalen) { | ||
| 193 | memcpy(data, buf->p, len); | ||
| 194 | data[len] = 0; | ||
| 195 | buf->p += len; | ||
| 196 | len++; | ||
| 197 | } | ||
| 198 | |||
| 199 | return len; | ||
| 200 | } | ||
| 201 | |||
| 202 | static inline char *buf_get_stringb(struct cbuf *buf, struct cbuf *sbuf) | ||
| 203 | { | ||
| 204 | char *ret; | ||
| 205 | u16 len; | ||
| 206 | |||
| 207 | ret = NULL; | ||
| 208 | len = buf_get_int16(buf); | ||
| 209 | |||
| 210 | if (!buf_check_overflow(buf) && buf_check_size(buf, len) && | ||
| 211 | buf_check_size(sbuf, len+1)) { | ||
| 212 | |||
| 213 | memcpy(sbuf->p, buf->p, len); | ||
| 214 | sbuf->p[len] = 0; | ||
| 215 | ret = sbuf->p; | ||
| 216 | buf->p += len; | ||
| 217 | sbuf->p += len + 1; | ||
| 218 | } | ||
| 219 | |||
| 220 | return ret; | ||
| 221 | } | ||
| 222 | |||
| 223 | static inline int buf_get_data(struct cbuf *buf, void *data, int datalen) | ||
| 224 | { | 182 | { |
| 225 | int ret = 0; | 183 | vstr->len = buf_get_int16(buf); |
| 226 | 184 | if (!buf_check_overflow(buf) && buf_check_size(buf, vstr->len)) { | |
| 227 | if (buf_check_size(buf, datalen)) { | 185 | vstr->str = buf->p; |
| 228 | memcpy(data, buf->p, datalen); | 186 | buf->p += vstr->len; |
| 229 | buf->p += datalen; | 187 | } else { |
| 230 | ret = datalen; | 188 | vstr->len = 0; |
| 189 | vstr->str = NULL; | ||
| 231 | } | 190 | } |
| 232 | |||
| 233 | return ret; | ||
| 234 | } | 191 | } |
| 235 | 192 | ||
| 236 | static inline void *buf_get_datab(struct cbuf *buf, struct cbuf *dbuf, | 193 | static void buf_get_qid(struct cbuf *bufp, struct v9fs_qid *qid) |
| 237 | int datalen) | ||
| 238 | { | 194 | { |
| 239 | char *ret = NULL; | 195 | qid->type = buf_get_int8(bufp); |
| 240 | int n = 0; | 196 | qid->version = buf_get_int32(bufp); |
| 241 | 197 | qid->path = buf_get_int64(bufp); | |
| 242 | if (buf_check_size(dbuf, datalen)) { | ||
| 243 | n = buf_get_data(buf, dbuf->p, datalen); | ||
| 244 | if (n > 0) { | ||
| 245 | ret = dbuf->p; | ||
| 246 | dbuf->p += n; | ||
| 247 | } | ||
| 248 | } | ||
| 249 | |||
| 250 | return ret; | ||
| 251 | } | 198 | } |
| 252 | 199 | ||
| 253 | /** | 200 | /** |
| 254 | * v9fs_size_stat - calculate the size of a variable length stat struct | 201 | * v9fs_size_wstat - calculate the size of a variable length stat struct |
| 255 | * @v9ses: session information | ||
| 256 | * @stat: metadata (stat) structure | 202 | * @stat: metadata (stat) structure |
| 203 | * @extended: non-zero if 9P2000.u | ||
| 257 | * | 204 | * |
| 258 | */ | 205 | */ |
| 259 | 206 | ||
| 260 | static int v9fs_size_stat(struct v9fs_session_info *v9ses, | 207 | static int v9fs_size_wstat(struct v9fs_wstat *wstat, int extended) |
| 261 | struct v9fs_stat *stat) | ||
| 262 | { | 208 | { |
| 263 | int size = 0; | 209 | int size = 0; |
| 264 | 210 | ||
| 265 | if (stat == NULL) { | 211 | if (wstat == NULL) { |
| 266 | eprintk(KERN_ERR, "v9fs_size_stat: got a NULL stat pointer\n"); | 212 | eprintk(KERN_ERR, "v9fs_size_stat: got a NULL stat pointer\n"); |
| 267 | return 0; | 213 | return 0; |
| 268 | } | 214 | } |
| @@ -279,82 +225,38 @@ static int v9fs_size_stat(struct v9fs_session_info *v9ses, | |||
| 279 | 8 + /* length[8] */ | 225 | 8 + /* length[8] */ |
| 280 | 8; /* minimum sum of string lengths */ | 226 | 8; /* minimum sum of string lengths */ |
| 281 | 227 | ||
| 282 | if (stat->name) | 228 | if (wstat->name) |
| 283 | size += strlen(stat->name); | 229 | size += strlen(wstat->name); |
| 284 | if (stat->uid) | 230 | if (wstat->uid) |
| 285 | size += strlen(stat->uid); | 231 | size += strlen(wstat->uid); |
| 286 | if (stat->gid) | 232 | if (wstat->gid) |
| 287 | size += strlen(stat->gid); | 233 | size += strlen(wstat->gid); |
| 288 | if (stat->muid) | 234 | if (wstat->muid) |
| 289 | size += strlen(stat->muid); | 235 | size += strlen(wstat->muid); |
| 290 | 236 | ||
| 291 | if (v9ses->extended) { | 237 | if (extended) { |
| 292 | size += 4 + /* n_uid[4] */ | 238 | size += 4 + /* n_uid[4] */ |
| 293 | 4 + /* n_gid[4] */ | 239 | 4 + /* n_gid[4] */ |
| 294 | 4 + /* n_muid[4] */ | 240 | 4 + /* n_muid[4] */ |
| 295 | 2; /* string length of extension[4] */ | 241 | 2; /* string length of extension[4] */ |
| 296 | if (stat->extension) | 242 | if (wstat->extension) |
| 297 | size += strlen(stat->extension); | 243 | size += strlen(wstat->extension); |
| 298 | } | 244 | } |
| 299 | 245 | ||
| 300 | return size; | 246 | return size; |
| 301 | } | 247 | } |
| 302 | 248 | ||
| 303 | /** | 249 | /** |
| 304 | * serialize_stat - safely format a stat structure for transmission | 250 | * buf_get_stat - safely decode a recieved metadata (stat) structure |
| 305 | * @v9ses: session info | ||
| 306 | * @stat: metadata (stat) structure | ||
| 307 | * @bufp: buffer to serialize structure into | ||
| 308 | * | ||
| 309 | */ | ||
| 310 | |||
| 311 | static int | ||
| 312 | serialize_stat(struct v9fs_session_info *v9ses, struct v9fs_stat *stat, | ||
| 313 | struct cbuf *bufp) | ||
| 314 | { | ||
| 315 | buf_put_int16(bufp, stat->size); | ||
| 316 | buf_put_int16(bufp, stat->type); | ||
| 317 | buf_put_int32(bufp, stat->dev); | ||
| 318 | buf_put_int8(bufp, stat->qid.type); | ||
| 319 | buf_put_int32(bufp, stat->qid.version); | ||
| 320 | buf_put_int64(bufp, stat->qid.path); | ||
| 321 | buf_put_int32(bufp, stat->mode); | ||
| 322 | buf_put_int32(bufp, stat->atime); | ||
| 323 | buf_put_int32(bufp, stat->mtime); | ||
| 324 | buf_put_int64(bufp, stat->length); | ||
| 325 | |||
| 326 | buf_put_string(bufp, stat->name); | ||
| 327 | buf_put_string(bufp, stat->uid); | ||
| 328 | buf_put_string(bufp, stat->gid); | ||
| 329 | buf_put_string(bufp, stat->muid); | ||
| 330 | |||
| 331 | if (v9ses->extended) { | ||
| 332 | buf_put_string(bufp, stat->extension); | ||
| 333 | buf_put_int32(bufp, stat->n_uid); | ||
| 334 | buf_put_int32(bufp, stat->n_gid); | ||
| 335 | buf_put_int32(bufp, stat->n_muid); | ||
| 336 | } | ||
| 337 | |||
| 338 | if (buf_check_overflow(bufp)) | ||
| 339 | return 0; | ||
| 340 | |||
| 341 | return stat->size; | ||
| 342 | } | ||
| 343 | |||
| 344 | /** | ||
| 345 | * deserialize_stat - safely decode a recieved metadata (stat) structure | ||
| 346 | * @v9ses: session info | ||
| 347 | * @bufp: buffer to deserialize | 251 | * @bufp: buffer to deserialize |
| 348 | * @stat: metadata (stat) structure | 252 | * @stat: metadata (stat) structure |
| 349 | * @dbufp: buffer to deserialize variable strings into | 253 | * @extended: non-zero if 9P2000.u |
| 350 | * | 254 | * |
| 351 | */ | 255 | */ |
| 352 | 256 | ||
| 353 | static inline int | 257 | static void |
| 354 | deserialize_stat(struct v9fs_session_info *v9ses, struct cbuf *bufp, | 258 | buf_get_stat(struct cbuf *bufp, struct v9fs_stat *stat, int extended) |
| 355 | struct v9fs_stat *stat, struct cbuf *dbufp) | ||
| 356 | { | 259 | { |
| 357 | |||
| 358 | stat->size = buf_get_int16(bufp); | 260 | stat->size = buf_get_int16(bufp); |
| 359 | stat->type = buf_get_int16(bufp); | 261 | stat->type = buf_get_int16(bufp); |
| 360 | stat->dev = buf_get_int32(bufp); | 262 | stat->dev = buf_get_int32(bufp); |
| @@ -365,282 +267,82 @@ deserialize_stat(struct v9fs_session_info *v9ses, struct cbuf *bufp, | |||
| 365 | stat->atime = buf_get_int32(bufp); | 267 | stat->atime = buf_get_int32(bufp); |
| 366 | stat->mtime = buf_get_int32(bufp); | 268 | stat->mtime = buf_get_int32(bufp); |
| 367 | stat->length = buf_get_int64(bufp); | 269 | stat->length = buf_get_int64(bufp); |
| 368 | stat->name = buf_get_stringb(bufp, dbufp); | 270 | buf_get_str(bufp, &stat->name); |
| 369 | stat->uid = buf_get_stringb(bufp, dbufp); | 271 | buf_get_str(bufp, &stat->uid); |
| 370 | stat->gid = buf_get_stringb(bufp, dbufp); | 272 | buf_get_str(bufp, &stat->gid); |
| 371 | stat->muid = buf_get_stringb(bufp, dbufp); | 273 | buf_get_str(bufp, &stat->muid); |
| 372 | 274 | ||
| 373 | if (v9ses->extended) { | 275 | if (extended) { |
| 374 | stat->extension = buf_get_stringb(bufp, dbufp); | 276 | buf_get_str(bufp, &stat->extension); |
| 375 | stat->n_uid = buf_get_int32(bufp); | 277 | stat->n_uid = buf_get_int32(bufp); |
| 376 | stat->n_gid = buf_get_int32(bufp); | 278 | stat->n_gid = buf_get_int32(bufp); |
| 377 | stat->n_muid = buf_get_int32(bufp); | 279 | stat->n_muid = buf_get_int32(bufp); |
| 378 | } | 280 | } |
| 379 | |||
| 380 | if (buf_check_overflow(bufp) || buf_check_overflow(dbufp)) | ||
| 381 | return 0; | ||
| 382 | |||
| 383 | return stat->size + 2; | ||
| 384 | } | ||
| 385 | |||
| 386 | /** | ||
| 387 | * deserialize_statb - wrapper for decoding a received metadata structure | ||
| 388 | * @v9ses: session info | ||
| 389 | * @bufp: buffer to deserialize | ||
| 390 | * @dbufp: buffer to deserialize variable strings into | ||
| 391 | * | ||
| 392 | */ | ||
| 393 | |||
| 394 | static inline struct v9fs_stat *deserialize_statb(struct v9fs_session_info | ||
| 395 | *v9ses, struct cbuf *bufp, | ||
| 396 | struct cbuf *dbufp) | ||
| 397 | { | ||
| 398 | struct v9fs_stat *ret = buf_alloc(dbufp, sizeof(struct v9fs_stat)); | ||
| 399 | |||
| 400 | if (ret) { | ||
| 401 | int n = deserialize_stat(v9ses, bufp, ret, dbufp); | ||
| 402 | if (n <= 0) | ||
| 403 | return NULL; | ||
| 404 | } | ||
| 405 | |||
| 406 | return ret; | ||
| 407 | } | 281 | } |
| 408 | 282 | ||
| 409 | /** | 283 | /** |
| 410 | * v9fs_deserialize_stat - decode a received metadata structure | 284 | * v9fs_deserialize_stat - decode a received metadata structure |
| 411 | * @v9ses: session info | ||
| 412 | * @buf: buffer to deserialize | 285 | * @buf: buffer to deserialize |
| 413 | * @buflen: length of received buffer | 286 | * @buflen: length of received buffer |
| 414 | * @stat: metadata structure to decode into | 287 | * @stat: metadata structure to decode into |
| 415 | * @statlen: length of destination metadata structure | 288 | * @extended: non-zero if 9P2000.u |
| 416 | * | 289 | * |
| 290 | * Note: stat will point to the buf region. | ||
| 417 | */ | 291 | */ |
| 418 | 292 | ||
| 419 | int | 293 | int |
| 420 | v9fs_deserialize_stat(struct v9fs_session_info *v9ses, void *buf, | 294 | v9fs_deserialize_stat(void *buf, u32 buflen, struct v9fs_stat *stat, |
| 421 | u32 buflen, struct v9fs_stat *stat, u32 statlen) | 295 | int extended) |
| 422 | { | 296 | { |
| 423 | struct cbuf buffer; | 297 | struct cbuf buffer; |
| 424 | struct cbuf *bufp = &buffer; | 298 | struct cbuf *bufp = &buffer; |
| 425 | struct cbuf dbuffer; | 299 | unsigned char *p; |
| 426 | struct cbuf *dbufp = &dbuffer; | ||
| 427 | 300 | ||
| 428 | buf_init(bufp, buf, buflen); | 301 | buf_init(bufp, buf, buflen); |
| 429 | buf_init(dbufp, (char *)stat + sizeof(struct v9fs_stat), | 302 | p = bufp->p; |
| 430 | statlen - sizeof(struct v9fs_stat)); | 303 | buf_get_stat(bufp, stat, extended); |
| 431 | |||
| 432 | return deserialize_stat(v9ses, bufp, stat, dbufp); | ||
| 433 | } | ||
| 434 | |||
| 435 | static inline int | ||
| 436 | v9fs_size_fcall(struct v9fs_session_info *v9ses, struct v9fs_fcall *fcall) | ||
| 437 | { | ||
| 438 | int size = 4 + 1 + 2; /* size[4] msg[1] tag[2] */ | ||
| 439 | int i = 0; | ||
| 440 | |||
| 441 | switch (fcall->id) { | ||
| 442 | default: | ||
| 443 | eprintk(KERN_ERR, "bad msg type %d\n", fcall->id); | ||
| 444 | return 0; | ||
| 445 | case TVERSION: /* msize[4] version[s] */ | ||
| 446 | size += 4 + 2 + strlen(fcall->params.tversion.version); | ||
| 447 | break; | ||
| 448 | case TAUTH: /* afid[4] uname[s] aname[s] */ | ||
| 449 | size += 4 + 2 + strlen(fcall->params.tauth.uname) + | ||
| 450 | 2 + strlen(fcall->params.tauth.aname); | ||
| 451 | break; | ||
| 452 | case TFLUSH: /* oldtag[2] */ | ||
| 453 | size += 2; | ||
| 454 | break; | ||
| 455 | case TATTACH: /* fid[4] afid[4] uname[s] aname[s] */ | ||
| 456 | size += 4 + 4 + 2 + strlen(fcall->params.tattach.uname) + | ||
| 457 | 2 + strlen(fcall->params.tattach.aname); | ||
| 458 | break; | ||
| 459 | case TWALK: /* fid[4] newfid[4] nwname[2] nwname*(wname[s]) */ | ||
| 460 | size += 4 + 4 + 2; | ||
| 461 | /* now compute total for the array of names */ | ||
| 462 | for (i = 0; i < fcall->params.twalk.nwname; i++) | ||
| 463 | size += 2 + strlen(fcall->params.twalk.wnames[i]); | ||
| 464 | break; | ||
| 465 | case TOPEN: /* fid[4] mode[1] */ | ||
| 466 | size += 4 + 1; | ||
| 467 | break; | ||
| 468 | case TCREATE: /* fid[4] name[s] perm[4] mode[1] */ | ||
| 469 | size += 4 + 2 + strlen(fcall->params.tcreate.name) + 4 + 1; | ||
| 470 | break; | ||
| 471 | case TREAD: /* fid[4] offset[8] count[4] */ | ||
| 472 | size += 4 + 8 + 4; | ||
| 473 | break; | ||
| 474 | case TWRITE: /* fid[4] offset[8] count[4] data[count] */ | ||
| 475 | size += 4 + 8 + 4 + fcall->params.twrite.count; | ||
| 476 | break; | ||
| 477 | case TCLUNK: /* fid[4] */ | ||
| 478 | size += 4; | ||
| 479 | break; | ||
| 480 | case TREMOVE: /* fid[4] */ | ||
| 481 | size += 4; | ||
| 482 | break; | ||
| 483 | case TSTAT: /* fid[4] */ | ||
| 484 | size += 4; | ||
| 485 | break; | ||
| 486 | case TWSTAT: /* fid[4] stat[n] */ | ||
| 487 | fcall->params.twstat.stat->size = | ||
| 488 | v9fs_size_stat(v9ses, fcall->params.twstat.stat); | ||
| 489 | size += 4 + 2 + 2 + fcall->params.twstat.stat->size; | ||
| 490 | } | ||
| 491 | return size; | ||
| 492 | } | ||
| 493 | |||
| 494 | /* | ||
| 495 | * v9fs_serialize_fcall - marshall fcall struct into a packet | ||
| 496 | * @v9ses: session information | ||
| 497 | * @fcall: structure to convert | ||
| 498 | * @data: buffer to serialize fcall into | ||
| 499 | * @datalen: length of buffer to serialize fcall into | ||
| 500 | * | ||
| 501 | */ | ||
| 502 | |||
| 503 | int | ||
| 504 | v9fs_serialize_fcall(struct v9fs_session_info *v9ses, struct v9fs_fcall *fcall, | ||
| 505 | void *data, u32 datalen) | ||
| 506 | { | ||
| 507 | int i = 0; | ||
| 508 | struct v9fs_stat *stat = NULL; | ||
| 509 | struct cbuf buffer; | ||
| 510 | struct cbuf *bufp = &buffer; | ||
| 511 | |||
| 512 | buf_init(bufp, data, datalen); | ||
| 513 | |||
| 514 | if (!fcall) { | ||
| 515 | eprintk(KERN_ERR, "no fcall\n"); | ||
| 516 | return -EINVAL; | ||
| 517 | } | ||
| 518 | |||
| 519 | fcall->size = v9fs_size_fcall(v9ses, fcall); | ||
| 520 | |||
| 521 | buf_put_int32(bufp, fcall->size); | ||
| 522 | buf_put_int8(bufp, fcall->id); | ||
| 523 | buf_put_int16(bufp, fcall->tag); | ||
| 524 | |||
| 525 | dprintk(DEBUG_CONV, "size %d id %d tag %d\n", fcall->size, fcall->id, | ||
| 526 | fcall->tag); | ||
| 527 | |||
| 528 | /* now encode it */ | ||
| 529 | switch (fcall->id) { | ||
| 530 | default: | ||
| 531 | eprintk(KERN_ERR, "bad msg type: %d\n", fcall->id); | ||
| 532 | return -EPROTO; | ||
| 533 | case TVERSION: | ||
| 534 | buf_put_int32(bufp, fcall->params.tversion.msize); | ||
| 535 | buf_put_string(bufp, fcall->params.tversion.version); | ||
| 536 | break; | ||
| 537 | case TAUTH: | ||
| 538 | buf_put_int32(bufp, fcall->params.tauth.afid); | ||
| 539 | buf_put_string(bufp, fcall->params.tauth.uname); | ||
| 540 | buf_put_string(bufp, fcall->params.tauth.aname); | ||
| 541 | break; | ||
| 542 | case TFLUSH: | ||
| 543 | buf_put_int16(bufp, fcall->params.tflush.oldtag); | ||
| 544 | break; | ||
| 545 | case TATTACH: | ||
| 546 | buf_put_int32(bufp, fcall->params.tattach.fid); | ||
| 547 | buf_put_int32(bufp, fcall->params.tattach.afid); | ||
| 548 | buf_put_string(bufp, fcall->params.tattach.uname); | ||
| 549 | buf_put_string(bufp, fcall->params.tattach.aname); | ||
| 550 | break; | ||
| 551 | case TWALK: | ||
| 552 | buf_put_int32(bufp, fcall->params.twalk.fid); | ||
| 553 | buf_put_int32(bufp, fcall->params.twalk.newfid); | ||
| 554 | buf_put_int16(bufp, fcall->params.twalk.nwname); | ||
| 555 | for (i = 0; i < fcall->params.twalk.nwname; i++) | ||
| 556 | buf_put_string(bufp, fcall->params.twalk.wnames[i]); | ||
| 557 | break; | ||
| 558 | case TOPEN: | ||
| 559 | buf_put_int32(bufp, fcall->params.topen.fid); | ||
| 560 | buf_put_int8(bufp, fcall->params.topen.mode); | ||
| 561 | break; | ||
| 562 | case TCREATE: | ||
| 563 | buf_put_int32(bufp, fcall->params.tcreate.fid); | ||
| 564 | buf_put_string(bufp, fcall->params.tcreate.name); | ||
| 565 | buf_put_int32(bufp, fcall->params.tcreate.perm); | ||
| 566 | buf_put_int8(bufp, fcall->params.tcreate.mode); | ||
| 567 | break; | ||
| 568 | case TREAD: | ||
| 569 | buf_put_int32(bufp, fcall->params.tread.fid); | ||
| 570 | buf_put_int64(bufp, fcall->params.tread.offset); | ||
| 571 | buf_put_int32(bufp, fcall->params.tread.count); | ||
| 572 | break; | ||
| 573 | case TWRITE: | ||
| 574 | buf_put_int32(bufp, fcall->params.twrite.fid); | ||
| 575 | buf_put_int64(bufp, fcall->params.twrite.offset); | ||
| 576 | buf_put_int32(bufp, fcall->params.twrite.count); | ||
| 577 | buf_put_data(bufp, fcall->params.twrite.data, | ||
| 578 | fcall->params.twrite.count); | ||
| 579 | break; | ||
| 580 | case TCLUNK: | ||
| 581 | buf_put_int32(bufp, fcall->params.tclunk.fid); | ||
| 582 | break; | ||
| 583 | case TREMOVE: | ||
| 584 | buf_put_int32(bufp, fcall->params.tremove.fid); | ||
| 585 | break; | ||
| 586 | case TSTAT: | ||
| 587 | buf_put_int32(bufp, fcall->params.tstat.fid); | ||
| 588 | break; | ||
| 589 | case TWSTAT: | ||
| 590 | buf_put_int32(bufp, fcall->params.twstat.fid); | ||
| 591 | stat = fcall->params.twstat.stat; | ||
| 592 | |||
| 593 | buf_put_int16(bufp, stat->size + 2); | ||
| 594 | serialize_stat(v9ses, stat, bufp); | ||
| 595 | break; | ||
| 596 | } | ||
| 597 | 304 | ||
| 598 | if (buf_check_overflow(bufp)) | 305 | if (buf_check_overflow(bufp)) |
| 599 | return -EIO; | 306 | return 0; |
| 600 | 307 | else | |
| 601 | return fcall->size; | 308 | return bufp->p - p; |
| 602 | } | 309 | } |
| 603 | 310 | ||
| 604 | /** | 311 | /** |
| 605 | * deserialize_fcall - unmarshal a response | 312 | * deserialize_fcall - unmarshal a response |
| 606 | * @v9ses: session information | ||
| 607 | * @msgsize: size of rcall message | ||
| 608 | * @buf: recieved buffer | 313 | * @buf: recieved buffer |
| 609 | * @buflen: length of received buffer | 314 | * @buflen: length of received buffer |
| 610 | * @rcall: fcall structure to populate | 315 | * @rcall: fcall structure to populate |
| 611 | * @rcalllen: length of fcall structure to populate | 316 | * @rcalllen: length of fcall structure to populate |
| 317 | * @extended: non-zero if 9P2000.u | ||
| 612 | * | 318 | * |
| 613 | */ | 319 | */ |
| 614 | 320 | ||
| 615 | int | 321 | int |
| 616 | v9fs_deserialize_fcall(struct v9fs_session_info *v9ses, u32 msgsize, | 322 | v9fs_deserialize_fcall(void *buf, u32 buflen, struct v9fs_fcall *rcall, |
| 617 | void *buf, u32 buflen, struct v9fs_fcall *rcall, | 323 | int extended) |
| 618 | int rcalllen) | ||
| 619 | { | 324 | { |
| 620 | 325 | ||
| 621 | struct cbuf buffer; | 326 | struct cbuf buffer; |
| 622 | struct cbuf *bufp = &buffer; | 327 | struct cbuf *bufp = &buffer; |
| 623 | struct cbuf dbuffer; | ||
| 624 | struct cbuf *dbufp = &dbuffer; | ||
| 625 | int i = 0; | 328 | int i = 0; |
| 626 | 329 | ||
| 627 | buf_init(bufp, buf, buflen); | 330 | buf_init(bufp, buf, buflen); |
| 628 | buf_init(dbufp, (char *)rcall + sizeof(struct v9fs_fcall), | ||
| 629 | rcalllen - sizeof(struct v9fs_fcall)); | ||
| 630 | 331 | ||
| 631 | rcall->size = msgsize; | 332 | rcall->size = buf_get_int32(bufp); |
| 632 | rcall->id = buf_get_int8(bufp); | 333 | rcall->id = buf_get_int8(bufp); |
| 633 | rcall->tag = buf_get_int16(bufp); | 334 | rcall->tag = buf_get_int16(bufp); |
| 634 | 335 | ||
| 635 | dprintk(DEBUG_CONV, "size %d id %d tag %d\n", rcall->size, rcall->id, | 336 | dprintk(DEBUG_CONV, "size %d id %d tag %d\n", rcall->size, rcall->id, |
| 636 | rcall->tag); | 337 | rcall->tag); |
| 338 | |||
| 637 | switch (rcall->id) { | 339 | switch (rcall->id) { |
| 638 | default: | 340 | default: |
| 639 | eprintk(KERN_ERR, "unknown message type: %d\n", rcall->id); | 341 | eprintk(KERN_ERR, "unknown message type: %d\n", rcall->id); |
| 640 | return -EPROTO; | 342 | return -EPROTO; |
| 641 | case RVERSION: | 343 | case RVERSION: |
| 642 | rcall->params.rversion.msize = buf_get_int32(bufp); | 344 | rcall->params.rversion.msize = buf_get_int32(bufp); |
| 643 | rcall->params.rversion.version = buf_get_stringb(bufp, dbufp); | 345 | buf_get_str(bufp, &rcall->params.rversion.version); |
| 644 | break; | 346 | break; |
| 645 | case RFLUSH: | 347 | case RFLUSH: |
| 646 | break; | 348 | break; |
| @@ -651,34 +353,27 @@ v9fs_deserialize_fcall(struct v9fs_session_info *v9ses, u32 msgsize, | |||
| 651 | break; | 353 | break; |
| 652 | case RWALK: | 354 | case RWALK: |
| 653 | rcall->params.rwalk.nwqid = buf_get_int16(bufp); | 355 | rcall->params.rwalk.nwqid = buf_get_int16(bufp); |
| 654 | rcall->params.rwalk.wqids = buf_alloc(dbufp, | 356 | if (rcall->params.rwalk.nwqid > V9FS_MAXWELEM) { |
| 655 | rcall->params.rwalk.nwqid * sizeof(struct v9fs_qid)); | 357 | eprintk(KERN_ERR, "Rwalk with more than %d qids: %d\n", |
| 656 | if (rcall->params.rwalk.wqids) | 358 | V9FS_MAXWELEM, rcall->params.rwalk.nwqid); |
| 657 | for (i = 0; i < rcall->params.rwalk.nwqid; i++) { | 359 | return -EPROTO; |
| 658 | rcall->params.rwalk.wqids[i].type = | 360 | } |
| 659 | buf_get_int8(bufp); | 361 | |
| 660 | rcall->params.rwalk.wqids[i].version = | 362 | for (i = 0; i < rcall->params.rwalk.nwqid; i++) |
| 661 | buf_get_int16(bufp); | 363 | buf_get_qid(bufp, &rcall->params.rwalk.wqids[i]); |
| 662 | rcall->params.rwalk.wqids[i].path = | ||
| 663 | buf_get_int64(bufp); | ||
| 664 | } | ||
| 665 | break; | 364 | break; |
| 666 | case ROPEN: | 365 | case ROPEN: |
| 667 | rcall->params.ropen.qid.type = buf_get_int8(bufp); | 366 | buf_get_qid(bufp, &rcall->params.ropen.qid); |
| 668 | rcall->params.ropen.qid.version = buf_get_int32(bufp); | ||
| 669 | rcall->params.ropen.qid.path = buf_get_int64(bufp); | ||
| 670 | rcall->params.ropen.iounit = buf_get_int32(bufp); | 367 | rcall->params.ropen.iounit = buf_get_int32(bufp); |
| 671 | break; | 368 | break; |
| 672 | case RCREATE: | 369 | case RCREATE: |
| 673 | rcall->params.rcreate.qid.type = buf_get_int8(bufp); | 370 | buf_get_qid(bufp, &rcall->params.rcreate.qid); |
| 674 | rcall->params.rcreate.qid.version = buf_get_int32(bufp); | ||
| 675 | rcall->params.rcreate.qid.path = buf_get_int64(bufp); | ||
| 676 | rcall->params.rcreate.iounit = buf_get_int32(bufp); | 371 | rcall->params.rcreate.iounit = buf_get_int32(bufp); |
| 677 | break; | 372 | break; |
| 678 | case RREAD: | 373 | case RREAD: |
| 679 | rcall->params.rread.count = buf_get_int32(bufp); | 374 | rcall->params.rread.count = buf_get_int32(bufp); |
| 680 | rcall->params.rread.data = buf_get_datab(bufp, dbufp, | 375 | rcall->params.rread.data = bufp->p; |
| 681 | rcall->params.rread.count); | 376 | buf_check_size(bufp, rcall->params.rread.count); |
| 682 | break; | 377 | break; |
| 683 | case RWRITE: | 378 | case RWRITE: |
| 684 | rcall->params.rwrite.count = buf_get_int32(bufp); | 379 | rcall->params.rwrite.count = buf_get_int32(bufp); |
| @@ -689,20 +384,443 @@ v9fs_deserialize_fcall(struct v9fs_session_info *v9ses, u32 msgsize, | |||
| 689 | break; | 384 | break; |
| 690 | case RSTAT: | 385 | case RSTAT: |
| 691 | buf_get_int16(bufp); | 386 | buf_get_int16(bufp); |
| 692 | rcall->params.rstat.stat = | 387 | buf_get_stat(bufp, &rcall->params.rstat.stat, extended); |
| 693 | deserialize_statb(v9ses, bufp, dbufp); | ||
| 694 | break; | 388 | break; |
| 695 | case RWSTAT: | 389 | case RWSTAT: |
| 696 | break; | 390 | break; |
| 697 | case RERROR: | 391 | case RERROR: |
| 698 | rcall->params.rerror.error = buf_get_stringb(bufp, dbufp); | 392 | buf_get_str(bufp, &rcall->params.rerror.error); |
| 699 | if (v9ses->extended) | 393 | if (extended) |
| 700 | rcall->params.rerror.errno = buf_get_int16(bufp); | 394 | rcall->params.rerror.errno = buf_get_int16(bufp); |
| 701 | break; | 395 | break; |
| 702 | } | 396 | } |
| 703 | 397 | ||
| 704 | if (buf_check_overflow(bufp) || buf_check_overflow(dbufp)) | 398 | if (buf_check_overflow(bufp)) { |
| 399 | dprintk(DEBUG_ERROR, "buffer overflow\n"); | ||
| 705 | return -EIO; | 400 | return -EIO; |
| 401 | } | ||
| 402 | |||
| 403 | return bufp->p - bufp->sp; | ||
| 404 | } | ||
| 405 | |||
| 406 | static inline void v9fs_put_int8(struct cbuf *bufp, u8 val, u8 * p) | ||
| 407 | { | ||
| 408 | *p = val; | ||
| 409 | buf_put_int8(bufp, val); | ||
| 410 | } | ||
| 411 | |||
| 412 | static inline void v9fs_put_int16(struct cbuf *bufp, u16 val, u16 * p) | ||
| 413 | { | ||
| 414 | *p = val; | ||
| 415 | buf_put_int16(bufp, val); | ||
| 416 | } | ||
| 417 | |||
| 418 | static inline void v9fs_put_int32(struct cbuf *bufp, u32 val, u32 * p) | ||
| 419 | { | ||
| 420 | *p = val; | ||
| 421 | buf_put_int32(bufp, val); | ||
| 422 | } | ||
| 423 | |||
| 424 | static inline void v9fs_put_int64(struct cbuf *bufp, u64 val, u64 * p) | ||
| 425 | { | ||
| 426 | *p = val; | ||
| 427 | buf_put_int64(bufp, val); | ||
| 428 | } | ||
| 429 | |||
| 430 | static void | ||
| 431 | v9fs_put_str(struct cbuf *bufp, char *data, struct v9fs_str *str) | ||
| 432 | { | ||
| 433 | if (data) { | ||
| 434 | str->len = strlen(data); | ||
| 435 | str->str = bufp->p; | ||
| 436 | } else { | ||
| 437 | str->len = 0; | ||
| 438 | str->str = NULL; | ||
| 439 | } | ||
| 440 | |||
| 441 | buf_put_stringn(bufp, data, str->len); | ||
| 442 | } | ||
| 443 | |||
| 444 | static int | ||
| 445 | v9fs_put_user_data(struct cbuf *bufp, const char __user * data, int count, | ||
| 446 | unsigned char **pdata) | ||
| 447 | { | ||
| 448 | *pdata = buf_alloc(bufp, count); | ||
| 449 | return copy_from_user(*pdata, data, count); | ||
| 450 | } | ||
| 451 | |||
| 452 | static void | ||
| 453 | v9fs_put_wstat(struct cbuf *bufp, struct v9fs_wstat *wstat, | ||
| 454 | struct v9fs_stat *stat, int statsz, int extended) | ||
| 455 | { | ||
| 456 | v9fs_put_int16(bufp, statsz, &stat->size); | ||
| 457 | v9fs_put_int16(bufp, wstat->type, &stat->type); | ||
| 458 | v9fs_put_int32(bufp, wstat->dev, &stat->dev); | ||
| 459 | v9fs_put_int8(bufp, wstat->qid.type, &stat->qid.type); | ||
| 460 | v9fs_put_int32(bufp, wstat->qid.version, &stat->qid.version); | ||
| 461 | v9fs_put_int64(bufp, wstat->qid.path, &stat->qid.path); | ||
| 462 | v9fs_put_int32(bufp, wstat->mode, &stat->mode); | ||
| 463 | v9fs_put_int32(bufp, wstat->atime, &stat->atime); | ||
| 464 | v9fs_put_int32(bufp, wstat->mtime, &stat->mtime); | ||
| 465 | v9fs_put_int64(bufp, wstat->length, &stat->length); | ||
| 466 | |||
| 467 | v9fs_put_str(bufp, wstat->name, &stat->name); | ||
| 468 | v9fs_put_str(bufp, wstat->uid, &stat->uid); | ||
| 469 | v9fs_put_str(bufp, wstat->gid, &stat->gid); | ||
| 470 | v9fs_put_str(bufp, wstat->muid, &stat->muid); | ||
| 471 | |||
| 472 | if (extended) { | ||
| 473 | v9fs_put_str(bufp, wstat->extension, &stat->extension); | ||
| 474 | v9fs_put_int32(bufp, wstat->n_uid, &stat->n_uid); | ||
| 475 | v9fs_put_int32(bufp, wstat->n_gid, &stat->n_gid); | ||
| 476 | v9fs_put_int32(bufp, wstat->n_muid, &stat->n_muid); | ||
| 477 | } | ||
| 478 | } | ||
| 479 | |||
| 480 | static struct v9fs_fcall * | ||
| 481 | v9fs_create_common(struct cbuf *bufp, u32 size, u8 id) | ||
| 482 | { | ||
| 483 | struct v9fs_fcall *fc; | ||
| 484 | |||
| 485 | size += 4 + 1 + 2; /* size[4] id[1] tag[2] */ | ||
| 486 | fc = kmalloc(sizeof(struct v9fs_fcall) + size, GFP_KERNEL); | ||
| 487 | if (!fc) | ||
| 488 | return ERR_PTR(-ENOMEM); | ||
| 489 | |||
| 490 | fc->sdata = (char *)fc + sizeof(*fc); | ||
| 491 | |||
| 492 | buf_init(bufp, (char *)fc->sdata, size); | ||
| 493 | v9fs_put_int32(bufp, size, &fc->size); | ||
| 494 | v9fs_put_int8(bufp, id, &fc->id); | ||
| 495 | v9fs_put_int16(bufp, V9FS_NOTAG, &fc->tag); | ||
| 496 | |||
| 497 | return fc; | ||
| 498 | } | ||
| 499 | |||
| 500 | void v9fs_set_tag(struct v9fs_fcall *fc, u16 tag) | ||
| 501 | { | ||
| 502 | fc->tag = tag; | ||
| 503 | *(__le16 *) (fc->sdata + 5) = cpu_to_le16(tag); | ||
| 504 | } | ||
| 505 | |||
| 506 | struct v9fs_fcall *v9fs_create_tversion(u32 msize, char *version) | ||
| 507 | { | ||
| 508 | int size; | ||
| 509 | struct v9fs_fcall *fc; | ||
| 510 | struct cbuf buffer; | ||
| 511 | struct cbuf *bufp = &buffer; | ||
| 512 | |||
| 513 | size = 4 + 2 + strlen(version); /* msize[4] version[s] */ | ||
| 514 | fc = v9fs_create_common(bufp, size, TVERSION); | ||
| 515 | if (IS_ERR(fc)) | ||
| 516 | goto error; | ||
| 517 | |||
| 518 | v9fs_put_int32(bufp, msize, &fc->params.tversion.msize); | ||
| 519 | v9fs_put_str(bufp, version, &fc->params.tversion.version); | ||
| 520 | |||
| 521 | if (buf_check_overflow(bufp)) { | ||
| 522 | kfree(fc); | ||
| 523 | fc = ERR_PTR(-ENOMEM); | ||
| 524 | } | ||
| 525 | error: | ||
| 526 | return fc; | ||
| 527 | } | ||
| 528 | |||
| 529 | struct v9fs_fcall *v9fs_create_tauth(u32 afid, char *uname, char *aname) | ||
| 530 | { | ||
| 531 | int size; | ||
| 532 | struct v9fs_fcall *fc; | ||
| 533 | struct cbuf buffer; | ||
| 534 | struct cbuf *bufp = &buffer; | ||
| 535 | |||
| 536 | size = 4 + 2 + strlen(uname) + 2 + strlen(aname); /* afid[4] uname[s] aname[s] */ | ||
| 537 | fc = v9fs_create_common(bufp, size, TAUTH); | ||
| 538 | if (IS_ERR(fc)) | ||
| 539 | goto error; | ||
| 540 | |||
| 541 | v9fs_put_int32(bufp, afid, &fc->params.tauth.afid); | ||
| 542 | v9fs_put_str(bufp, uname, &fc->params.tauth.uname); | ||
| 543 | v9fs_put_str(bufp, aname, &fc->params.tauth.aname); | ||
| 544 | |||
| 545 | if (buf_check_overflow(bufp)) { | ||
| 546 | kfree(fc); | ||
| 547 | fc = ERR_PTR(-ENOMEM); | ||
| 548 | } | ||
| 549 | error: | ||
| 550 | return fc; | ||
| 551 | } | ||
| 552 | |||
| 553 | struct v9fs_fcall * | ||
| 554 | v9fs_create_tattach(u32 fid, u32 afid, char *uname, char *aname) | ||
| 555 | { | ||
| 556 | int size; | ||
| 557 | struct v9fs_fcall *fc; | ||
| 558 | struct cbuf buffer; | ||
| 559 | struct cbuf *bufp = &buffer; | ||
| 560 | |||
| 561 | size = 4 + 4 + 2 + strlen(uname) + 2 + strlen(aname); /* fid[4] afid[4] uname[s] aname[s] */ | ||
| 562 | fc = v9fs_create_common(bufp, size, TATTACH); | ||
| 563 | if (IS_ERR(fc)) | ||
| 564 | goto error; | ||
| 565 | |||
| 566 | v9fs_put_int32(bufp, fid, &fc->params.tattach.fid); | ||
| 567 | v9fs_put_int32(bufp, afid, &fc->params.tattach.afid); | ||
| 568 | v9fs_put_str(bufp, uname, &fc->params.tattach.uname); | ||
| 569 | v9fs_put_str(bufp, aname, &fc->params.tattach.aname); | ||
| 570 | |||
| 571 | error: | ||
| 572 | return fc; | ||
| 573 | } | ||
| 574 | |||
| 575 | struct v9fs_fcall *v9fs_create_tflush(u16 oldtag) | ||
| 576 | { | ||
| 577 | int size; | ||
| 578 | struct v9fs_fcall *fc; | ||
| 579 | struct cbuf buffer; | ||
| 580 | struct cbuf *bufp = &buffer; | ||
| 581 | |||
| 582 | size = 2; /* oldtag[2] */ | ||
| 583 | fc = v9fs_create_common(bufp, size, TFLUSH); | ||
| 584 | if (IS_ERR(fc)) | ||
| 585 | goto error; | ||
| 586 | |||
| 587 | v9fs_put_int16(bufp, oldtag, &fc->params.tflush.oldtag); | ||
| 588 | |||
| 589 | if (buf_check_overflow(bufp)) { | ||
| 590 | kfree(fc); | ||
| 591 | fc = ERR_PTR(-ENOMEM); | ||
| 592 | } | ||
| 593 | error: | ||
| 594 | return fc; | ||
| 595 | } | ||
| 596 | |||
| 597 | struct v9fs_fcall *v9fs_create_twalk(u32 fid, u32 newfid, u16 nwname, | ||
| 598 | char **wnames) | ||
| 599 | { | ||
| 600 | int i, size; | ||
| 601 | struct v9fs_fcall *fc; | ||
| 602 | struct cbuf buffer; | ||
| 603 | struct cbuf *bufp = &buffer; | ||
| 604 | |||
| 605 | if (nwname > V9FS_MAXWELEM) { | ||
| 606 | dprintk(DEBUG_ERROR, "nwname > %d\n", V9FS_MAXWELEM); | ||
| 607 | return NULL; | ||
| 608 | } | ||
| 609 | |||
| 610 | size = 4 + 4 + 2; /* fid[4] newfid[4] nwname[2] ... */ | ||
| 611 | for (i = 0; i < nwname; i++) { | ||
| 612 | size += 2 + strlen(wnames[i]); /* wname[s] */ | ||
| 613 | } | ||
| 614 | |||
| 615 | fc = v9fs_create_common(bufp, size, TWALK); | ||
| 616 | if (IS_ERR(fc)) | ||
| 617 | goto error; | ||
| 618 | |||
| 619 | v9fs_put_int32(bufp, fid, &fc->params.twalk.fid); | ||
| 620 | v9fs_put_int32(bufp, newfid, &fc->params.twalk.newfid); | ||
| 621 | v9fs_put_int16(bufp, nwname, &fc->params.twalk.nwname); | ||
| 622 | for (i = 0; i < nwname; i++) { | ||
| 623 | v9fs_put_str(bufp, wnames[i], &fc->params.twalk.wnames[i]); | ||
| 624 | } | ||
| 625 | |||
| 626 | if (buf_check_overflow(bufp)) { | ||
| 627 | kfree(fc); | ||
| 628 | fc = ERR_PTR(-ENOMEM); | ||
| 629 | } | ||
| 630 | error: | ||
| 631 | return fc; | ||
| 632 | } | ||
| 706 | 633 | ||
| 707 | return rcall->size; | 634 | struct v9fs_fcall *v9fs_create_topen(u32 fid, u8 mode) |
| 635 | { | ||
| 636 | int size; | ||
| 637 | struct v9fs_fcall *fc; | ||
| 638 | struct cbuf buffer; | ||
| 639 | struct cbuf *bufp = &buffer; | ||
| 640 | |||
| 641 | size = 4 + 1; /* fid[4] mode[1] */ | ||
| 642 | fc = v9fs_create_common(bufp, size, TOPEN); | ||
| 643 | if (IS_ERR(fc)) | ||
| 644 | goto error; | ||
| 645 | |||
| 646 | v9fs_put_int32(bufp, fid, &fc->params.topen.fid); | ||
| 647 | v9fs_put_int8(bufp, mode, &fc->params.topen.mode); | ||
| 648 | |||
| 649 | if (buf_check_overflow(bufp)) { | ||
| 650 | kfree(fc); | ||
| 651 | fc = ERR_PTR(-ENOMEM); | ||
| 652 | } | ||
| 653 | error: | ||
| 654 | return fc; | ||
| 655 | } | ||
| 656 | |||
| 657 | struct v9fs_fcall *v9fs_create_tcreate(u32 fid, char *name, u32 perm, u8 mode) | ||
| 658 | { | ||
| 659 | int size; | ||
| 660 | struct v9fs_fcall *fc; | ||
| 661 | struct cbuf buffer; | ||
| 662 | struct cbuf *bufp = &buffer; | ||
| 663 | |||
| 664 | size = 4 + 2 + strlen(name) + 4 + 1; /* fid[4] name[s] perm[4] mode[1] */ | ||
| 665 | fc = v9fs_create_common(bufp, size, TCREATE); | ||
| 666 | if (IS_ERR(fc)) | ||
| 667 | goto error; | ||
| 668 | |||
| 669 | v9fs_put_int32(bufp, fid, &fc->params.tcreate.fid); | ||
| 670 | v9fs_put_str(bufp, name, &fc->params.tcreate.name); | ||
| 671 | v9fs_put_int32(bufp, perm, &fc->params.tcreate.perm); | ||
| 672 | v9fs_put_int8(bufp, mode, &fc->params.tcreate.mode); | ||
| 673 | |||
| 674 | if (buf_check_overflow(bufp)) { | ||
| 675 | kfree(fc); | ||
| 676 | fc = ERR_PTR(-ENOMEM); | ||
| 677 | } | ||
| 678 | error: | ||
| 679 | return fc; | ||
| 680 | } | ||
| 681 | |||
| 682 | struct v9fs_fcall *v9fs_create_tread(u32 fid, u64 offset, u32 count) | ||
| 683 | { | ||
| 684 | int size; | ||
| 685 | struct v9fs_fcall *fc; | ||
| 686 | struct cbuf buffer; | ||
| 687 | struct cbuf *bufp = &buffer; | ||
| 688 | |||
| 689 | size = 4 + 8 + 4; /* fid[4] offset[8] count[4] */ | ||
| 690 | fc = v9fs_create_common(bufp, size, TREAD); | ||
| 691 | if (IS_ERR(fc)) | ||
| 692 | goto error; | ||
| 693 | |||
| 694 | v9fs_put_int32(bufp, fid, &fc->params.tread.fid); | ||
| 695 | v9fs_put_int64(bufp, offset, &fc->params.tread.offset); | ||
| 696 | v9fs_put_int32(bufp, count, &fc->params.tread.count); | ||
| 697 | |||
| 698 | if (buf_check_overflow(bufp)) { | ||
| 699 | kfree(fc); | ||
| 700 | fc = ERR_PTR(-ENOMEM); | ||
| 701 | } | ||
| 702 | error: | ||
| 703 | return fc; | ||
| 704 | } | ||
| 705 | |||
| 706 | struct v9fs_fcall *v9fs_create_twrite(u32 fid, u64 offset, u32 count, | ||
| 707 | const char __user * data) | ||
| 708 | { | ||
| 709 | int size, err; | ||
| 710 | struct v9fs_fcall *fc; | ||
| 711 | struct cbuf buffer; | ||
| 712 | struct cbuf *bufp = &buffer; | ||
| 713 | |||
| 714 | size = 4 + 8 + 4 + count; /* fid[4] offset[8] count[4] data[count] */ | ||
| 715 | fc = v9fs_create_common(bufp, size, TWRITE); | ||
| 716 | if (IS_ERR(fc)) | ||
| 717 | goto error; | ||
| 718 | |||
| 719 | v9fs_put_int32(bufp, fid, &fc->params.twrite.fid); | ||
| 720 | v9fs_put_int64(bufp, offset, &fc->params.twrite.offset); | ||
| 721 | v9fs_put_int32(bufp, count, &fc->params.twrite.count); | ||
| 722 | err = v9fs_put_user_data(bufp, data, count, &fc->params.twrite.data); | ||
| 723 | if (err) { | ||
| 724 | kfree(fc); | ||
| 725 | fc = ERR_PTR(err); | ||
| 726 | } | ||
| 727 | |||
| 728 | if (buf_check_overflow(bufp)) { | ||
| 729 | kfree(fc); | ||
| 730 | fc = ERR_PTR(-ENOMEM); | ||
| 731 | } | ||
| 732 | error: | ||
| 733 | return fc; | ||
| 734 | } | ||
| 735 | |||
| 736 | struct v9fs_fcall *v9fs_create_tclunk(u32 fid) | ||
| 737 | { | ||
| 738 | int size; | ||
| 739 | struct v9fs_fcall *fc; | ||
| 740 | struct cbuf buffer; | ||
| 741 | struct cbuf *bufp = &buffer; | ||
| 742 | |||
| 743 | size = 4; /* fid[4] */ | ||
| 744 | fc = v9fs_create_common(bufp, size, TCLUNK); | ||
| 745 | if (IS_ERR(fc)) | ||
| 746 | goto error; | ||
| 747 | |||
| 748 | v9fs_put_int32(bufp, fid, &fc->params.tclunk.fid); | ||
| 749 | |||
| 750 | if (buf_check_overflow(bufp)) { | ||
| 751 | kfree(fc); | ||
| 752 | fc = ERR_PTR(-ENOMEM); | ||
| 753 | } | ||
| 754 | error: | ||
| 755 | return fc; | ||
| 756 | } | ||
| 757 | |||
| 758 | struct v9fs_fcall *v9fs_create_tremove(u32 fid) | ||
| 759 | { | ||
| 760 | int size; | ||
| 761 | struct v9fs_fcall *fc; | ||
| 762 | struct cbuf buffer; | ||
| 763 | struct cbuf *bufp = &buffer; | ||
| 764 | |||
| 765 | size = 4; /* fid[4] */ | ||
| 766 | fc = v9fs_create_common(bufp, size, TREMOVE); | ||
| 767 | if (IS_ERR(fc)) | ||
| 768 | goto error; | ||
| 769 | |||
| 770 | v9fs_put_int32(bufp, fid, &fc->params.tremove.fid); | ||
| 771 | |||
| 772 | if (buf_check_overflow(bufp)) { | ||
| 773 | kfree(fc); | ||
| 774 | fc = ERR_PTR(-ENOMEM); | ||
| 775 | } | ||
| 776 | error: | ||
| 777 | return fc; | ||
| 778 | } | ||
| 779 | |||
| 780 | struct v9fs_fcall *v9fs_create_tstat(u32 fid) | ||
| 781 | { | ||
| 782 | int size; | ||
| 783 | struct v9fs_fcall *fc; | ||
| 784 | struct cbuf buffer; | ||
| 785 | struct cbuf *bufp = &buffer; | ||
| 786 | |||
| 787 | size = 4; /* fid[4] */ | ||
| 788 | fc = v9fs_create_common(bufp, size, TSTAT); | ||
| 789 | if (IS_ERR(fc)) | ||
| 790 | goto error; | ||
| 791 | |||
| 792 | v9fs_put_int32(bufp, fid, &fc->params.tstat.fid); | ||
| 793 | |||
| 794 | if (buf_check_overflow(bufp)) { | ||
| 795 | kfree(fc); | ||
| 796 | fc = ERR_PTR(-ENOMEM); | ||
| 797 | } | ||
| 798 | error: | ||
| 799 | return fc; | ||
| 800 | } | ||
| 801 | |||
| 802 | struct v9fs_fcall *v9fs_create_twstat(u32 fid, struct v9fs_wstat *wstat, | ||
| 803 | int extended) | ||
| 804 | { | ||
| 805 | int size, statsz; | ||
| 806 | struct v9fs_fcall *fc; | ||
| 807 | struct cbuf buffer; | ||
| 808 | struct cbuf *bufp = &buffer; | ||
| 809 | |||
| 810 | statsz = v9fs_size_wstat(wstat, extended); | ||
| 811 | size = 4 + 2 + 2 + statsz; /* fid[4] stat[n] */ | ||
| 812 | fc = v9fs_create_common(bufp, size, TWSTAT); | ||
| 813 | if (IS_ERR(fc)) | ||
| 814 | goto error; | ||
| 815 | |||
| 816 | v9fs_put_int32(bufp, fid, &fc->params.twstat.fid); | ||
| 817 | buf_put_int16(bufp, statsz + 2); | ||
| 818 | v9fs_put_wstat(bufp, wstat, &fc->params.twstat.stat, statsz, extended); | ||
| 819 | |||
| 820 | if (buf_check_overflow(bufp)) { | ||
| 821 | kfree(fc); | ||
| 822 | fc = ERR_PTR(-ENOMEM); | ||
| 823 | } | ||
| 824 | error: | ||
| 825 | return fc; | ||
| 708 | } | 826 | } |
