Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/net/9p/protocol.c
26282 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* 9P Protocol Support Code
4
*
5
* Copyright (C) 2008 by Eric Van Hensbergen <[email protected]>
6
*
7
* Base on code from Anthony Liguori <[email protected]>
8
* Copyright (C) 2008 by IBM, Corp.
9
*/
10
11
#include <linux/module.h>
12
#include <linux/errno.h>
13
#include <linux/kernel.h>
14
#include <linux/uaccess.h>
15
#include <linux/slab.h>
16
#include <linux/sched.h>
17
#include <linux/stddef.h>
18
#include <linux/types.h>
19
#include <linux/uio.h>
20
#include <net/9p/9p.h>
21
#include <net/9p/client.h>
22
#include "protocol.h"
23
24
#include <trace/events/9p.h>
25
26
/* len[2] text[len] */
27
#define P9_STRLEN(s) \
28
(2 + min_t(size_t, s ? strlen(s) : 0, USHRT_MAX))
29
30
/**
31
* p9_msg_buf_size - Returns a buffer size sufficiently large to hold the
32
* intended 9p message.
33
* @c: client
34
* @type: message type
35
* @fmt: format template for assembling request message
36
* (see p9pdu_vwritef)
37
* @ap: variable arguments to be fed to passed format template
38
* (see p9pdu_vwritef)
39
*
40
* Note: Even for response types (P9_R*) the format template and variable
41
* arguments must always be for the originating request type (P9_T*).
42
*/
43
size_t p9_msg_buf_size(struct p9_client *c, enum p9_msg_t type,
44
const char *fmt, va_list ap)
45
{
46
/* size[4] type[1] tag[2] */
47
const int hdr = 4 + 1 + 2;
48
/* ename[s] errno[4] */
49
const int rerror_size = hdr + P9_ERRMAX + 4;
50
/* ecode[4] */
51
const int rlerror_size = hdr + 4;
52
const int err_size =
53
c->proto_version == p9_proto_2000L ? rlerror_size : rerror_size;
54
55
static_assert(NAME_MAX <= 4*1024, "p9_msg_buf_size() currently assumes "
56
"a max. allowed directory entry name length of 4k");
57
58
switch (type) {
59
60
/* message types not used at all */
61
case P9_TERROR:
62
case P9_TLERROR:
63
case P9_TAUTH:
64
case P9_RAUTH:
65
BUG();
66
67
/* variable length & potentially large message types */
68
case P9_TATTACH:
69
BUG_ON(strcmp("ddss?u", fmt));
70
va_arg(ap, int32_t);
71
va_arg(ap, int32_t);
72
{
73
const char *uname = va_arg(ap, const char *);
74
const char *aname = va_arg(ap, const char *);
75
/* fid[4] afid[4] uname[s] aname[s] n_uname[4] */
76
return hdr + 4 + 4 + P9_STRLEN(uname) + P9_STRLEN(aname) + 4;
77
}
78
case P9_TWALK:
79
BUG_ON(strcmp("ddT", fmt));
80
va_arg(ap, int32_t);
81
va_arg(ap, int32_t);
82
{
83
uint i, nwname = va_arg(ap, int);
84
size_t wname_all;
85
const char **wnames = va_arg(ap, const char **);
86
for (i = 0, wname_all = 0; i < nwname; ++i) {
87
wname_all += P9_STRLEN(wnames[i]);
88
}
89
/* fid[4] newfid[4] nwname[2] nwname*(wname[s]) */
90
return hdr + 4 + 4 + 2 + wname_all;
91
}
92
case P9_RWALK:
93
BUG_ON(strcmp("ddT", fmt));
94
va_arg(ap, int32_t);
95
va_arg(ap, int32_t);
96
{
97
uint nwname = va_arg(ap, int);
98
/* nwqid[2] nwqid*(wqid[13]) */
99
return max_t(size_t, hdr + 2 + nwname * 13, err_size);
100
}
101
case P9_TCREATE:
102
BUG_ON(strcmp("dsdb?s", fmt));
103
va_arg(ap, int32_t);
104
{
105
const char *name = va_arg(ap, const char *);
106
if (c->proto_version == p9_proto_legacy) {
107
/* fid[4] name[s] perm[4] mode[1] */
108
return hdr + 4 + P9_STRLEN(name) + 4 + 1;
109
} else {
110
va_arg(ap, int32_t);
111
va_arg(ap, int);
112
{
113
const char *ext = va_arg(ap, const char *);
114
/* fid[4] name[s] perm[4] mode[1] extension[s] */
115
return hdr + 4 + P9_STRLEN(name) + 4 + 1 + P9_STRLEN(ext);
116
}
117
}
118
}
119
case P9_TLCREATE:
120
BUG_ON(strcmp("dsddg", fmt));
121
va_arg(ap, int32_t);
122
{
123
const char *name = va_arg(ap, const char *);
124
/* fid[4] name[s] flags[4] mode[4] gid[4] */
125
return hdr + 4 + P9_STRLEN(name) + 4 + 4 + 4;
126
}
127
case P9_RREAD:
128
case P9_RREADDIR:
129
BUG_ON(strcmp("dqd", fmt));
130
va_arg(ap, int32_t);
131
va_arg(ap, int64_t);
132
{
133
const int32_t count = va_arg(ap, int32_t);
134
/* count[4] data[count] */
135
return max_t(size_t, hdr + 4 + count, err_size);
136
}
137
case P9_TWRITE:
138
BUG_ON(strcmp("dqV", fmt));
139
va_arg(ap, int32_t);
140
va_arg(ap, int64_t);
141
{
142
const int32_t count = va_arg(ap, int32_t);
143
/* fid[4] offset[8] count[4] data[count] */
144
return hdr + 4 + 8 + 4 + count;
145
}
146
case P9_TRENAMEAT:
147
BUG_ON(strcmp("dsds", fmt));
148
va_arg(ap, int32_t);
149
{
150
const char *oldname, *newname;
151
oldname = va_arg(ap, const char *);
152
va_arg(ap, int32_t);
153
newname = va_arg(ap, const char *);
154
/* olddirfid[4] oldname[s] newdirfid[4] newname[s] */
155
return hdr + 4 + P9_STRLEN(oldname) + 4 + P9_STRLEN(newname);
156
}
157
case P9_TSYMLINK:
158
BUG_ON(strcmp("dssg", fmt));
159
va_arg(ap, int32_t);
160
{
161
const char *name = va_arg(ap, const char *);
162
const char *symtgt = va_arg(ap, const char *);
163
/* fid[4] name[s] symtgt[s] gid[4] */
164
return hdr + 4 + P9_STRLEN(name) + P9_STRLEN(symtgt) + 4;
165
}
166
167
case P9_RERROR:
168
return rerror_size;
169
case P9_RLERROR:
170
return rlerror_size;
171
172
/* small message types */
173
case P9_TWSTAT:
174
case P9_RSTAT:
175
case P9_RREADLINK:
176
case P9_TXATTRWALK:
177
case P9_TXATTRCREATE:
178
case P9_TLINK:
179
case P9_TMKDIR:
180
case P9_TMKNOD:
181
case P9_TRENAME:
182
case P9_TUNLINKAT:
183
case P9_TLOCK:
184
return 8 * 1024;
185
186
/* tiny message types */
187
default:
188
return 4 * 1024;
189
190
}
191
}
192
193
static int
194
p9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...);
195
196
void p9stat_free(struct p9_wstat *stbuf)
197
{
198
kfree(stbuf->name);
199
stbuf->name = NULL;
200
kfree(stbuf->uid);
201
stbuf->uid = NULL;
202
kfree(stbuf->gid);
203
stbuf->gid = NULL;
204
kfree(stbuf->muid);
205
stbuf->muid = NULL;
206
kfree(stbuf->extension);
207
stbuf->extension = NULL;
208
}
209
EXPORT_SYMBOL(p9stat_free);
210
211
size_t pdu_read(struct p9_fcall *pdu, void *data, size_t size)
212
{
213
size_t len = min(pdu->size - pdu->offset, size);
214
215
memcpy(data, &pdu->sdata[pdu->offset], len);
216
pdu->offset += len;
217
return size - len;
218
}
219
220
static size_t pdu_write(struct p9_fcall *pdu, const void *data, size_t size)
221
{
222
size_t len = min(pdu->capacity - pdu->size, size);
223
224
memcpy(&pdu->sdata[pdu->size], data, len);
225
pdu->size += len;
226
return size - len;
227
}
228
229
static size_t
230
pdu_write_u(struct p9_fcall *pdu, struct iov_iter *from, size_t size)
231
{
232
size_t len = min(pdu->capacity - pdu->size, size);
233
234
if (!copy_from_iter_full(&pdu->sdata[pdu->size], len, from))
235
len = 0;
236
237
pdu->size += len;
238
return size - len;
239
}
240
241
/* b - int8_t
242
* w - int16_t
243
* d - int32_t
244
* q - int64_t
245
* s - string
246
* u - numeric uid
247
* g - numeric gid
248
* S - stat
249
* Q - qid
250
* D - data blob (int32_t size followed by void *, results are not freed)
251
* T - array of strings (int16_t count, followed by strings)
252
* R - array of qids (int16_t count, followed by qids)
253
* A - stat for 9p2000.L (p9_stat_dotl)
254
* ? - if optional = 1, continue parsing
255
*/
256
257
static int
258
p9pdu_vreadf(struct p9_fcall *pdu, int proto_version, const char *fmt,
259
va_list ap)
260
{
261
const char *ptr;
262
int errcode = 0;
263
264
for (ptr = fmt; *ptr; ptr++) {
265
switch (*ptr) {
266
case 'b':{
267
int8_t *val = va_arg(ap, int8_t *);
268
if (pdu_read(pdu, val, sizeof(*val))) {
269
errcode = -EFAULT;
270
break;
271
}
272
}
273
break;
274
case 'w':{
275
int16_t *val = va_arg(ap, int16_t *);
276
__le16 le_val;
277
if (pdu_read(pdu, &le_val, sizeof(le_val))) {
278
errcode = -EFAULT;
279
break;
280
}
281
*val = le16_to_cpu(le_val);
282
}
283
break;
284
case 'd':{
285
int32_t *val = va_arg(ap, int32_t *);
286
__le32 le_val;
287
if (pdu_read(pdu, &le_val, sizeof(le_val))) {
288
errcode = -EFAULT;
289
break;
290
}
291
*val = le32_to_cpu(le_val);
292
}
293
break;
294
case 'q':{
295
int64_t *val = va_arg(ap, int64_t *);
296
__le64 le_val;
297
if (pdu_read(pdu, &le_val, sizeof(le_val))) {
298
errcode = -EFAULT;
299
break;
300
}
301
*val = le64_to_cpu(le_val);
302
}
303
break;
304
case 's':{
305
char **sptr = va_arg(ap, char **);
306
uint16_t len;
307
308
errcode = p9pdu_readf(pdu, proto_version,
309
"w", &len);
310
if (errcode)
311
break;
312
313
*sptr = kmalloc(len + 1, GFP_NOFS);
314
if (*sptr == NULL) {
315
errcode = -ENOMEM;
316
break;
317
}
318
if (pdu_read(pdu, *sptr, len)) {
319
errcode = -EFAULT;
320
kfree(*sptr);
321
*sptr = NULL;
322
} else
323
(*sptr)[len] = 0;
324
}
325
break;
326
case 'u': {
327
kuid_t *uid = va_arg(ap, kuid_t *);
328
__le32 le_val;
329
if (pdu_read(pdu, &le_val, sizeof(le_val))) {
330
errcode = -EFAULT;
331
break;
332
}
333
*uid = make_kuid(&init_user_ns,
334
le32_to_cpu(le_val));
335
} break;
336
case 'g': {
337
kgid_t *gid = va_arg(ap, kgid_t *);
338
__le32 le_val;
339
if (pdu_read(pdu, &le_val, sizeof(le_val))) {
340
errcode = -EFAULT;
341
break;
342
}
343
*gid = make_kgid(&init_user_ns,
344
le32_to_cpu(le_val));
345
} break;
346
case 'Q':{
347
struct p9_qid *qid =
348
va_arg(ap, struct p9_qid *);
349
350
errcode = p9pdu_readf(pdu, proto_version, "bdq",
351
&qid->type, &qid->version,
352
&qid->path);
353
}
354
break;
355
case 'S':{
356
struct p9_wstat *stbuf =
357
va_arg(ap, struct p9_wstat *);
358
359
memset(stbuf, 0, sizeof(struct p9_wstat));
360
stbuf->n_uid = stbuf->n_muid = INVALID_UID;
361
stbuf->n_gid = INVALID_GID;
362
363
errcode =
364
p9pdu_readf(pdu, proto_version,
365
"wwdQdddqssss?sugu",
366
&stbuf->size, &stbuf->type,
367
&stbuf->dev, &stbuf->qid,
368
&stbuf->mode, &stbuf->atime,
369
&stbuf->mtime, &stbuf->length,
370
&stbuf->name, &stbuf->uid,
371
&stbuf->gid, &stbuf->muid,
372
&stbuf->extension,
373
&stbuf->n_uid, &stbuf->n_gid,
374
&stbuf->n_muid);
375
if (errcode)
376
p9stat_free(stbuf);
377
}
378
break;
379
case 'D':{
380
uint32_t *count = va_arg(ap, uint32_t *);
381
void **data = va_arg(ap, void **);
382
383
errcode =
384
p9pdu_readf(pdu, proto_version, "d", count);
385
if (!errcode) {
386
*count =
387
min_t(uint32_t, *count,
388
pdu->size - pdu->offset);
389
*data = &pdu->sdata[pdu->offset];
390
}
391
}
392
break;
393
case 'T':{
394
uint16_t *nwname = va_arg(ap, uint16_t *);
395
char ***wnames = va_arg(ap, char ***);
396
397
*wnames = NULL;
398
399
errcode = p9pdu_readf(pdu, proto_version,
400
"w", nwname);
401
if (!errcode) {
402
*wnames =
403
kmalloc_array(*nwname,
404
sizeof(char *),
405
GFP_NOFS);
406
if (!*wnames)
407
errcode = -ENOMEM;
408
else
409
(*wnames)[0] = NULL;
410
}
411
412
if (!errcode) {
413
int i;
414
415
for (i = 0; i < *nwname; i++) {
416
errcode =
417
p9pdu_readf(pdu,
418
proto_version,
419
"s",
420
&(*wnames)[i]);
421
if (errcode) {
422
(*wnames)[i] = NULL;
423
break;
424
}
425
}
426
}
427
428
if (errcode) {
429
if (*wnames) {
430
int i;
431
432
for (i = 0; i < *nwname; i++) {
433
if (!(*wnames)[i])
434
break;
435
kfree((*wnames)[i]);
436
}
437
kfree(*wnames);
438
*wnames = NULL;
439
}
440
}
441
}
442
break;
443
case 'R':{
444
uint16_t *nwqid = va_arg(ap, uint16_t *);
445
struct p9_qid **wqids =
446
va_arg(ap, struct p9_qid **);
447
448
*wqids = NULL;
449
450
errcode =
451
p9pdu_readf(pdu, proto_version, "w", nwqid);
452
if (!errcode) {
453
*wqids =
454
kmalloc_array(*nwqid,
455
sizeof(struct p9_qid),
456
GFP_NOFS);
457
if (*wqids == NULL)
458
errcode = -ENOMEM;
459
}
460
461
if (!errcode) {
462
int i;
463
464
for (i = 0; i < *nwqid; i++) {
465
errcode =
466
p9pdu_readf(pdu,
467
proto_version,
468
"Q",
469
&(*wqids)[i]);
470
if (errcode)
471
break;
472
}
473
}
474
475
if (errcode) {
476
kfree(*wqids);
477
*wqids = NULL;
478
}
479
}
480
break;
481
case 'A': {
482
struct p9_stat_dotl *stbuf =
483
va_arg(ap, struct p9_stat_dotl *);
484
485
memset(stbuf, 0, sizeof(struct p9_stat_dotl));
486
errcode =
487
p9pdu_readf(pdu, proto_version,
488
"qQdugqqqqqqqqqqqqqqq",
489
&stbuf->st_result_mask,
490
&stbuf->qid,
491
&stbuf->st_mode,
492
&stbuf->st_uid, &stbuf->st_gid,
493
&stbuf->st_nlink,
494
&stbuf->st_rdev, &stbuf->st_size,
495
&stbuf->st_blksize, &stbuf->st_blocks,
496
&stbuf->st_atime_sec,
497
&stbuf->st_atime_nsec,
498
&stbuf->st_mtime_sec,
499
&stbuf->st_mtime_nsec,
500
&stbuf->st_ctime_sec,
501
&stbuf->st_ctime_nsec,
502
&stbuf->st_btime_sec,
503
&stbuf->st_btime_nsec,
504
&stbuf->st_gen,
505
&stbuf->st_data_version);
506
}
507
break;
508
case '?':
509
if ((proto_version != p9_proto_2000u) &&
510
(proto_version != p9_proto_2000L))
511
return 0;
512
break;
513
default:
514
BUG();
515
break;
516
}
517
518
if (errcode)
519
break;
520
}
521
522
return errcode;
523
}
524
525
int
526
p9pdu_vwritef(struct p9_fcall *pdu, int proto_version, const char *fmt,
527
va_list ap)
528
{
529
const char *ptr;
530
int errcode = 0;
531
532
for (ptr = fmt; *ptr; ptr++) {
533
switch (*ptr) {
534
case 'b':{
535
int8_t val = va_arg(ap, int);
536
if (pdu_write(pdu, &val, sizeof(val)))
537
errcode = -EFAULT;
538
}
539
break;
540
case 'w':{
541
__le16 val = cpu_to_le16(va_arg(ap, int));
542
if (pdu_write(pdu, &val, sizeof(val)))
543
errcode = -EFAULT;
544
}
545
break;
546
case 'd':{
547
__le32 val = cpu_to_le32(va_arg(ap, int32_t));
548
if (pdu_write(pdu, &val, sizeof(val)))
549
errcode = -EFAULT;
550
}
551
break;
552
case 'q':{
553
__le64 val = cpu_to_le64(va_arg(ap, int64_t));
554
if (pdu_write(pdu, &val, sizeof(val)))
555
errcode = -EFAULT;
556
}
557
break;
558
case 's':{
559
const char *sptr = va_arg(ap, const char *);
560
uint16_t len = 0;
561
if (sptr)
562
len = min_t(size_t, strlen(sptr),
563
USHRT_MAX);
564
565
errcode = p9pdu_writef(pdu, proto_version,
566
"w", len);
567
if (!errcode && pdu_write(pdu, sptr, len))
568
errcode = -EFAULT;
569
}
570
break;
571
case 'u': {
572
kuid_t uid = va_arg(ap, kuid_t);
573
__le32 val = cpu_to_le32(
574
from_kuid(&init_user_ns, uid));
575
if (pdu_write(pdu, &val, sizeof(val)))
576
errcode = -EFAULT;
577
} break;
578
case 'g': {
579
kgid_t gid = va_arg(ap, kgid_t);
580
__le32 val = cpu_to_le32(
581
from_kgid(&init_user_ns, gid));
582
if (pdu_write(pdu, &val, sizeof(val)))
583
errcode = -EFAULT;
584
} break;
585
case 'Q':{
586
const struct p9_qid *qid =
587
va_arg(ap, const struct p9_qid *);
588
errcode =
589
p9pdu_writef(pdu, proto_version, "bdq",
590
qid->type, qid->version,
591
qid->path);
592
} break;
593
case 'S':{
594
const struct p9_wstat *stbuf =
595
va_arg(ap, const struct p9_wstat *);
596
errcode =
597
p9pdu_writef(pdu, proto_version,
598
"wwdQdddqssss?sugu",
599
stbuf->size, stbuf->type,
600
stbuf->dev, &stbuf->qid,
601
stbuf->mode, stbuf->atime,
602
stbuf->mtime, stbuf->length,
603
stbuf->name, stbuf->uid,
604
stbuf->gid, stbuf->muid,
605
stbuf->extension, stbuf->n_uid,
606
stbuf->n_gid, stbuf->n_muid);
607
} break;
608
case 'V':{
609
uint32_t count = va_arg(ap, uint32_t);
610
struct iov_iter *from =
611
va_arg(ap, struct iov_iter *);
612
errcode = p9pdu_writef(pdu, proto_version, "d",
613
count);
614
if (!errcode && pdu_write_u(pdu, from, count))
615
errcode = -EFAULT;
616
}
617
break;
618
case 'T':{
619
uint16_t nwname = va_arg(ap, int);
620
const char **wnames = va_arg(ap, const char **);
621
622
errcode = p9pdu_writef(pdu, proto_version, "w",
623
nwname);
624
if (!errcode) {
625
int i;
626
627
for (i = 0; i < nwname; i++) {
628
errcode =
629
p9pdu_writef(pdu,
630
proto_version,
631
"s",
632
wnames[i]);
633
if (errcode)
634
break;
635
}
636
}
637
}
638
break;
639
case 'R':{
640
uint16_t nwqid = va_arg(ap, int);
641
struct p9_qid *wqids =
642
va_arg(ap, struct p9_qid *);
643
644
errcode = p9pdu_writef(pdu, proto_version, "w",
645
nwqid);
646
if (!errcode) {
647
int i;
648
649
for (i = 0; i < nwqid; i++) {
650
errcode =
651
p9pdu_writef(pdu,
652
proto_version,
653
"Q",
654
&wqids[i]);
655
if (errcode)
656
break;
657
}
658
}
659
}
660
break;
661
case 'I':{
662
struct p9_iattr_dotl *p9attr = va_arg(ap,
663
struct p9_iattr_dotl *);
664
665
errcode = p9pdu_writef(pdu, proto_version,
666
"ddugqqqqq",
667
p9attr->valid,
668
p9attr->mode,
669
p9attr->uid,
670
p9attr->gid,
671
p9attr->size,
672
p9attr->atime_sec,
673
p9attr->atime_nsec,
674
p9attr->mtime_sec,
675
p9attr->mtime_nsec);
676
}
677
break;
678
case '?':
679
if ((proto_version != p9_proto_2000u) &&
680
(proto_version != p9_proto_2000L))
681
return 0;
682
break;
683
default:
684
BUG();
685
break;
686
}
687
688
if (errcode)
689
break;
690
}
691
692
return errcode;
693
}
694
695
int p9pdu_readf(struct p9_fcall *pdu, int proto_version, const char *fmt, ...)
696
{
697
va_list ap;
698
int ret;
699
700
va_start(ap, fmt);
701
ret = p9pdu_vreadf(pdu, proto_version, fmt, ap);
702
va_end(ap);
703
704
return ret;
705
}
706
707
static int
708
p9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...)
709
{
710
va_list ap;
711
int ret;
712
713
va_start(ap, fmt);
714
ret = p9pdu_vwritef(pdu, proto_version, fmt, ap);
715
va_end(ap);
716
717
return ret;
718
}
719
720
int p9stat_read(struct p9_client *clnt, char *buf, int len, struct p9_wstat *st)
721
{
722
struct p9_fcall fake_pdu;
723
int ret;
724
725
fake_pdu.size = len;
726
fake_pdu.capacity = len;
727
fake_pdu.sdata = buf;
728
fake_pdu.offset = 0;
729
730
ret = p9pdu_readf(&fake_pdu, clnt->proto_version, "S", st);
731
if (ret) {
732
p9_debug(P9_DEBUG_9P, "<<< p9stat_read failed: %d\n", ret);
733
trace_9p_protocol_dump(clnt, &fake_pdu);
734
return ret;
735
}
736
737
return fake_pdu.offset;
738
}
739
EXPORT_SYMBOL(p9stat_read);
740
741
int p9pdu_prepare(struct p9_fcall *pdu, int16_t tag, int8_t type)
742
{
743
pdu->id = type;
744
return p9pdu_writef(pdu, 0, "dbw", 0, type, tag);
745
}
746
747
int p9pdu_finalize(struct p9_client *clnt, struct p9_fcall *pdu)
748
{
749
int size = pdu->size;
750
int err;
751
752
pdu->size = 0;
753
err = p9pdu_writef(pdu, 0, "d", size);
754
pdu->size = size;
755
756
trace_9p_protocol_dump(clnt, pdu);
757
p9_debug(P9_DEBUG_9P, ">>> size=%d type: %d tag: %d\n",
758
pdu->size, pdu->id, pdu->tag);
759
760
return err;
761
}
762
763
void p9pdu_reset(struct p9_fcall *pdu)
764
{
765
pdu->offset = 0;
766
pdu->size = 0;
767
}
768
769
int p9dirent_read(struct p9_client *clnt, char *buf, int len,
770
struct p9_dirent *dirent)
771
{
772
struct p9_fcall fake_pdu;
773
int ret;
774
char *nameptr;
775
776
fake_pdu.size = len;
777
fake_pdu.capacity = len;
778
fake_pdu.sdata = buf;
779
fake_pdu.offset = 0;
780
781
ret = p9pdu_readf(&fake_pdu, clnt->proto_version, "Qqbs", &dirent->qid,
782
&dirent->d_off, &dirent->d_type, &nameptr);
783
if (ret) {
784
p9_debug(P9_DEBUG_9P, "<<< p9dirent_read failed: %d\n", ret);
785
trace_9p_protocol_dump(clnt, &fake_pdu);
786
return ret;
787
}
788
789
ret = strscpy(dirent->d_name, nameptr, sizeof(dirent->d_name));
790
if (ret < 0) {
791
p9_debug(P9_DEBUG_ERROR,
792
"On the wire dirent name too long: %s\n",
793
nameptr);
794
kfree(nameptr);
795
return ret;
796
}
797
kfree(nameptr);
798
799
return fake_pdu.offset;
800
}
801
EXPORT_SYMBOL(p9dirent_read);
802
803