Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/lib9p/request.c
39475 views
1
/*
2
* Copyright 2016 Jakub Klama <[email protected]>
3
* All rights reserved
4
*
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted providing that the following conditions
7
* are met:
8
* 1. Redistributions of source code must retain the above copyright
9
* notice, this list of conditions and the following disclaimer.
10
* 2. Redistributions in binary form must reproduce the above copyright
11
* notice, this list of conditions and the following disclaimer in the
12
* documentation and/or other materials provided with the distribution.
13
*
14
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
18
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
22
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
23
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24
* POSSIBILITY OF SUCH DAMAGE.
25
*
26
*/
27
28
#include <stdlib.h>
29
#include <string.h>
30
#include <assert.h>
31
#include <errno.h>
32
#include <sys/param.h>
33
#include <sys/uio.h>
34
#if defined(__FreeBSD__)
35
#include <sys/sbuf.h>
36
#else
37
#include "sbuf/sbuf.h"
38
#endif
39
#include "lib9p.h"
40
#include "lib9p_impl.h"
41
#include "fcall.h"
42
#include "fid.h"
43
#include "hashtable.h"
44
#include "log.h"
45
#include "linux_errno.h"
46
#include "backend/backend.h"
47
#include "threadpool.h"
48
49
#define N(x) (sizeof(x) / sizeof(x[0]))
50
51
static int l9p_dispatch_tversion(struct l9p_request *req);
52
static int l9p_dispatch_tattach(struct l9p_request *req);
53
static int l9p_dispatch_tclunk(struct l9p_request *req);
54
static int l9p_dispatch_tcreate(struct l9p_request *req);
55
static int l9p_dispatch_topen(struct l9p_request *req);
56
static int l9p_dispatch_tread(struct l9p_request *req);
57
static int l9p_dispatch_tremove(struct l9p_request *req);
58
static int l9p_dispatch_tstat(struct l9p_request *req);
59
static int l9p_dispatch_twalk(struct l9p_request *req);
60
static int l9p_dispatch_twrite(struct l9p_request *req);
61
static int l9p_dispatch_twstat(struct l9p_request *req);
62
static int l9p_dispatch_tstatfs(struct l9p_request *req);
63
static int l9p_dispatch_tlopen(struct l9p_request *req);
64
static int l9p_dispatch_tlcreate(struct l9p_request *req);
65
static int l9p_dispatch_tsymlink(struct l9p_request *req);
66
static int l9p_dispatch_tmknod(struct l9p_request *req);
67
static int l9p_dispatch_trename(struct l9p_request *req);
68
static int l9p_dispatch_treadlink(struct l9p_request *req);
69
static int l9p_dispatch_tgetattr(struct l9p_request *req);
70
static int l9p_dispatch_tsetattr(struct l9p_request *req);
71
static int l9p_dispatch_txattrwalk(struct l9p_request *req);
72
static int l9p_dispatch_txattrcreate(struct l9p_request *req);
73
static int l9p_dispatch_treaddir(struct l9p_request *req);
74
static int l9p_dispatch_tfsync(struct l9p_request *req);
75
static int l9p_dispatch_tlock(struct l9p_request *req);
76
static int l9p_dispatch_tgetlock(struct l9p_request *req);
77
static int l9p_dispatch_tlink(struct l9p_request *req);
78
static int l9p_dispatch_tmkdir(struct l9p_request *req);
79
static int l9p_dispatch_trenameat(struct l9p_request *req);
80
static int l9p_dispatch_tunlinkat(struct l9p_request *req);
81
82
/*
83
* Each Txxx handler has a "must run" flag. If it is false,
84
* we check for a flush request before calling the handler.
85
* If a flush is already requested we can instantly fail the
86
* request with EINTR.
87
*
88
* Tclunk and Tremove must run because they make their fids
89
* become invalid. Tversion and Tattach should never get
90
* a flush request applied (it makes no sense as the connection
91
* is not really running yet), so it should be harmless to
92
* set them either way, but for now we have them as must-run.
93
* Flushing a Tflush is not really allowed either so we keep
94
* these as must-run too (although they run without being done
95
* threaded anyway).
96
*/
97
struct l9p_handler {
98
enum l9p_ftype type;
99
int (*handler)(struct l9p_request *);
100
bool must_run;
101
};
102
103
static const struct l9p_handler l9p_handlers_no_version[] = {
104
{L9P_TVERSION, l9p_dispatch_tversion, true},
105
};
106
107
static const struct l9p_handler l9p_handlers_base[] = {
108
{L9P_TVERSION, l9p_dispatch_tversion, true},
109
{L9P_TATTACH, l9p_dispatch_tattach, true},
110
{L9P_TCLUNK, l9p_dispatch_tclunk, true},
111
{L9P_TFLUSH, l9p_threadpool_tflush, true},
112
{L9P_TCREATE, l9p_dispatch_tcreate, false},
113
{L9P_TOPEN, l9p_dispatch_topen, false},
114
{L9P_TREAD, l9p_dispatch_tread, false},
115
{L9P_TWRITE, l9p_dispatch_twrite, false},
116
{L9P_TREMOVE, l9p_dispatch_tremove, true},
117
{L9P_TSTAT, l9p_dispatch_tstat, false},
118
{L9P_TWALK, l9p_dispatch_twalk, false},
119
{L9P_TWSTAT, l9p_dispatch_twstat, false}
120
};
121
static const struct l9p_handler l9p_handlers_dotu[] = {
122
{L9P_TVERSION, l9p_dispatch_tversion, true},
123
{L9P_TATTACH, l9p_dispatch_tattach, true},
124
{L9P_TCLUNK, l9p_dispatch_tclunk, true},
125
{L9P_TFLUSH, l9p_threadpool_tflush, true},
126
{L9P_TCREATE, l9p_dispatch_tcreate, false},
127
{L9P_TOPEN, l9p_dispatch_topen, false},
128
{L9P_TREAD, l9p_dispatch_tread, false},
129
{L9P_TWRITE, l9p_dispatch_twrite, false},
130
{L9P_TREMOVE, l9p_dispatch_tremove, true},
131
{L9P_TSTAT, l9p_dispatch_tstat, false},
132
{L9P_TWALK, l9p_dispatch_twalk, false},
133
{L9P_TWSTAT, l9p_dispatch_twstat, false}
134
};
135
static const struct l9p_handler l9p_handlers_dotL[] = {
136
{L9P_TVERSION, l9p_dispatch_tversion, true},
137
{L9P_TATTACH, l9p_dispatch_tattach, true},
138
{L9P_TCLUNK, l9p_dispatch_tclunk, true},
139
{L9P_TFLUSH, l9p_threadpool_tflush, true},
140
{L9P_TCREATE, l9p_dispatch_tcreate, false},
141
{L9P_TOPEN, l9p_dispatch_topen, false},
142
{L9P_TREAD, l9p_dispatch_tread, false},
143
{L9P_TWRITE, l9p_dispatch_twrite, false},
144
{L9P_TREMOVE, l9p_dispatch_tremove, true},
145
{L9P_TSTAT, l9p_dispatch_tstat, false},
146
{L9P_TWALK, l9p_dispatch_twalk, false},
147
{L9P_TWSTAT, l9p_dispatch_twstat, false},
148
{L9P_TSTATFS, l9p_dispatch_tstatfs, false},
149
{L9P_TLOPEN, l9p_dispatch_tlopen, false},
150
{L9P_TLCREATE, l9p_dispatch_tlcreate, false},
151
{L9P_TSYMLINK, l9p_dispatch_tsymlink, false},
152
{L9P_TMKNOD, l9p_dispatch_tmknod, false},
153
{L9P_TRENAME, l9p_dispatch_trename, false},
154
{L9P_TREADLINK, l9p_dispatch_treadlink, false},
155
{L9P_TGETATTR, l9p_dispatch_tgetattr, false},
156
{L9P_TSETATTR, l9p_dispatch_tsetattr, false},
157
{L9P_TXATTRWALK, l9p_dispatch_txattrwalk, false},
158
{L9P_TXATTRCREATE, l9p_dispatch_txattrcreate, false},
159
{L9P_TREADDIR, l9p_dispatch_treaddir, false},
160
{L9P_TFSYNC, l9p_dispatch_tfsync, false},
161
{L9P_TLOCK, l9p_dispatch_tlock, true},
162
{L9P_TGETLOCK, l9p_dispatch_tgetlock, true},
163
{L9P_TLINK, l9p_dispatch_tlink, false},
164
{L9P_TMKDIR, l9p_dispatch_tmkdir, false},
165
{L9P_TRENAMEAT, l9p_dispatch_trenameat, false},
166
{L9P_TUNLINKAT, l9p_dispatch_tunlinkat, false},
167
};
168
169
/*
170
* NB: version index 0 is reserved for new connections, and
171
* is a protocol that handles only L9P_TVERSION. Once we get a
172
* valid version, we start a new session using its dispatch table.
173
*/
174
static const struct {
175
const char *name;
176
const struct l9p_handler *handlers;
177
int n_handlers;
178
} l9p_versions[] = {
179
{ "<none>", l9p_handlers_no_version, N(l9p_handlers_no_version) },
180
{ "9P2000", l9p_handlers_base, N(l9p_handlers_base) },
181
{ "9P2000.u", l9p_handlers_dotu, N(l9p_handlers_dotu), },
182
{ "9P2000.L", l9p_handlers_dotL, N(l9p_handlers_dotL), },
183
};
184
185
/*
186
* Run the appropriate handler for this request.
187
* It's our caller's responsibility to respond.
188
*/
189
int
190
l9p_dispatch_request(struct l9p_request *req)
191
{
192
struct l9p_connection *conn;
193
#if defined(L9P_DEBUG)
194
struct sbuf *sb;
195
#endif
196
size_t i, n;
197
const struct l9p_handler *handlers, *hp;
198
bool flush_requested;
199
200
conn = req->lr_conn;
201
flush_requested = req->lr_flushstate == L9P_FLUSH_REQUESTED_PRE_START;
202
203
handlers = l9p_versions[conn->lc_version].handlers;
204
n = (size_t)l9p_versions[conn->lc_version].n_handlers;
205
for (hp = handlers, i = 0; i < n; hp++, i++)
206
if (req->lr_req.hdr.type == hp->type)
207
goto found;
208
hp = NULL;
209
found:
210
211
#if defined(L9P_DEBUG)
212
sb = sbuf_new_auto();
213
if (flush_requested) {
214
sbuf_cat(sb, "FLUSH requested pre-dispatch");
215
if (hp != NULL && hp->must_run)
216
sbuf_cat(sb, ", but must run");
217
sbuf_cat(sb, ": ");
218
}
219
l9p_describe_fcall(&req->lr_req, conn->lc_version, sb);
220
sbuf_finish(sb);
221
222
L9P_LOG(L9P_DEBUG, "%s", sbuf_data(sb));
223
sbuf_delete(sb);
224
#endif
225
226
if (hp != NULL) {
227
if (!flush_requested || hp->must_run)
228
return (hp->handler(req));
229
return (EINTR);
230
}
231
232
L9P_LOG(L9P_WARNING, "unknown request of type %d",
233
req->lr_req.hdr.type);
234
return (ENOSYS);
235
}
236
237
/*
238
* Translate BSD errno to 9P2000/9P2000.u errno.
239
*/
240
static inline int
241
e29p(int errnum)
242
{
243
static int const table[] = {
244
[ENOTEMPTY] = EPERM,
245
[EDQUOT] = EPERM,
246
[ENOSYS] = EPERM, /* ??? */
247
};
248
249
if ((size_t)errnum < N(table) && table[errnum] != 0)
250
return (table[errnum]);
251
if (errnum <= ERANGE)
252
return (errnum);
253
return (EIO); /* ??? */
254
}
255
256
/*
257
* Translate BSD errno to Linux errno.
258
*/
259
static inline int
260
e2linux(int errnum)
261
{
262
static int const table[] = {
263
[EDEADLK] = LINUX_EDEADLK,
264
[EAGAIN] = LINUX_EAGAIN,
265
[EINPROGRESS] = LINUX_EINPROGRESS,
266
[EALREADY] = LINUX_EALREADY,
267
[ENOTSOCK] = LINUX_ENOTSOCK,
268
[EDESTADDRREQ] = LINUX_EDESTADDRREQ,
269
[EMSGSIZE] = LINUX_EMSGSIZE,
270
[EPROTOTYPE] = LINUX_EPROTOTYPE,
271
[ENOPROTOOPT] = LINUX_ENOPROTOOPT,
272
[EPROTONOSUPPORT] = LINUX_EPROTONOSUPPORT,
273
[ESOCKTNOSUPPORT] = LINUX_ESOCKTNOSUPPORT,
274
[EOPNOTSUPP] = LINUX_EOPNOTSUPP,
275
[EPFNOSUPPORT] = LINUX_EPFNOSUPPORT,
276
[EAFNOSUPPORT] = LINUX_EAFNOSUPPORT,
277
[EADDRINUSE] = LINUX_EADDRINUSE,
278
[EADDRNOTAVAIL] = LINUX_EADDRNOTAVAIL,
279
[ENETDOWN] = LINUX_ENETDOWN,
280
[ENETUNREACH] = LINUX_ENETUNREACH,
281
[ENETRESET] = LINUX_ENETRESET,
282
[ECONNABORTED] = LINUX_ECONNABORTED,
283
[ECONNRESET] = LINUX_ECONNRESET,
284
[ENOBUFS] = LINUX_ENOBUFS,
285
[EISCONN] = LINUX_EISCONN,
286
[ENOTCONN] = LINUX_ENOTCONN,
287
[ESHUTDOWN] = LINUX_ESHUTDOWN,
288
[ETOOMANYREFS] = LINUX_ETOOMANYREFS,
289
[ETIMEDOUT] = LINUX_ETIMEDOUT,
290
[ECONNREFUSED] = LINUX_ECONNREFUSED,
291
[ELOOP] = LINUX_ELOOP,
292
[ENAMETOOLONG] = LINUX_ENAMETOOLONG,
293
[EHOSTDOWN] = LINUX_EHOSTDOWN,
294
[EHOSTUNREACH] = LINUX_EHOSTUNREACH,
295
[ENOTEMPTY] = LINUX_ENOTEMPTY,
296
[EPROCLIM] = LINUX_EAGAIN,
297
[EUSERS] = LINUX_EUSERS,
298
[EDQUOT] = LINUX_EDQUOT,
299
[ESTALE] = LINUX_ESTALE,
300
[EREMOTE] = LINUX_EREMOTE,
301
/* EBADRPC = unmappable? */
302
/* ERPCMISMATCH = unmappable? */
303
/* EPROGUNAVAIL = unmappable? */
304
/* EPROGMISMATCH = unmappable? */
305
/* EPROCUNAVAIL = unmappable? */
306
[ENOLCK] = LINUX_ENOLCK,
307
[ENOSYS] = LINUX_ENOSYS,
308
/* EFTYPE = unmappable? */
309
/* EAUTH = unmappable? */
310
/* ENEEDAUTH = unmappable? */
311
[EIDRM] = LINUX_EIDRM,
312
[ENOMSG] = LINUX_ENOMSG,
313
[EOVERFLOW] = LINUX_EOVERFLOW,
314
[ECANCELED] = LINUX_ECANCELED,
315
[EILSEQ] = LINUX_EILSEQ,
316
/* EDOOFUS = unmappable? */
317
[EBADMSG] = LINUX_EBADMSG,
318
[EMULTIHOP] = LINUX_EMULTIHOP,
319
[ENOLINK] = LINUX_ENOLINK,
320
[EPROTO] = LINUX_EPROTO,
321
/* ENOTCAPABLE = unmappable? */
322
#ifdef ECAPMODE
323
[ECAPMODE] = EPERM,
324
#endif
325
#ifdef ENOTRECOVERABLE
326
[ENOTRECOVERABLE] = LINUX_ENOTRECOVERABLE,
327
#endif
328
#ifdef EOWNERDEAD
329
[EOWNERDEAD] = LINUX_EOWNERDEAD,
330
#endif
331
};
332
333
/*
334
* In case we want to return a raw Linux errno, allow negative
335
* values a la Linux kernel internals.
336
*
337
* Values up to ERANGE are shared across systems (see
338
* linux_errno.h), except for EAGAIN.
339
*/
340
if (errnum < 0)
341
return (-errnum);
342
343
if ((size_t)errnum < N(table) && table[errnum] != 0)
344
return (table[errnum]);
345
346
if (errnum <= ERANGE)
347
return (errnum);
348
349
L9P_LOG(L9P_WARNING, "cannot map errno %d to anything reasonable",
350
errnum);
351
352
return (LINUX_ENOTRECOVERABLE); /* ??? */
353
}
354
355
/*
356
* Send response to request, or possibly just drop request.
357
* We also need to know whether to remove the request from
358
* the tag hash table.
359
*/
360
void
361
l9p_respond(struct l9p_request *req, bool drop, bool rmtag)
362
{
363
struct l9p_connection *conn = req->lr_conn;
364
size_t iosize;
365
#if defined(L9P_DEBUG)
366
struct sbuf *sb;
367
const char *ftype;
368
#endif
369
int error;
370
371
req->lr_resp.hdr.tag = req->lr_req.hdr.tag;
372
373
error = req->lr_error;
374
if (error == 0)
375
req->lr_resp.hdr.type = req->lr_req.hdr.type + 1;
376
else {
377
if (conn->lc_version == L9P_2000L) {
378
req->lr_resp.hdr.type = L9P_RLERROR;
379
req->lr_resp.error.errnum = (uint32_t)e2linux(error);
380
} else {
381
req->lr_resp.hdr.type = L9P_RERROR;
382
req->lr_resp.error.ename = strerror(error);
383
req->lr_resp.error.errnum = (uint32_t)e29p(error);
384
}
385
}
386
387
#if defined(L9P_DEBUG)
388
sb = sbuf_new_auto();
389
l9p_describe_fcall(&req->lr_resp, conn->lc_version, sb);
390
sbuf_finish(sb);
391
392
switch (req->lr_flushstate) {
393
case L9P_FLUSH_NONE:
394
ftype = "";
395
break;
396
case L9P_FLUSH_REQUESTED_PRE_START:
397
ftype = "FLUSH requested pre-dispatch: ";
398
break;
399
case L9P_FLUSH_REQUESTED_POST_START:
400
ftype = "FLUSH requested while running: ";
401
break;
402
case L9P_FLUSH_TOOLATE:
403
ftype = "FLUSH requested too late: ";
404
break;
405
}
406
L9P_LOG(L9P_DEBUG, "%s%s%s",
407
drop ? "DROP: " : "", ftype, sbuf_data(sb));
408
sbuf_delete(sb);
409
#endif
410
411
error = drop ? 0 :
412
l9p_pufcall(&req->lr_resp_msg, &req->lr_resp, conn->lc_version);
413
if (rmtag)
414
ht_remove(&conn->lc_requests, req->lr_req.hdr.tag);
415
if (error != 0) {
416
L9P_LOG(L9P_ERROR, "cannot pack response");
417
drop = true;
418
}
419
420
if (drop) {
421
conn->lc_lt.lt_drop_response(req,
422
req->lr_resp_msg.lm_iov, req->lr_resp_msg.lm_niov,
423
conn->lc_lt.lt_aux);
424
} else {
425
iosize = req->lr_resp_msg.lm_size;
426
427
/*
428
* Include I/O size in calculation for Rread and
429
* Rreaddir responses.
430
*/
431
if (req->lr_resp.hdr.type == L9P_RREAD ||
432
req->lr_resp.hdr.type == L9P_RREADDIR)
433
iosize += req->lr_resp.io.count;
434
435
conn->lc_lt.lt_send_response(req,
436
req->lr_resp_msg.lm_iov, req->lr_resp_msg.lm_niov,
437
iosize, conn->lc_lt.lt_aux);
438
}
439
440
l9p_freefcall(&req->lr_req);
441
l9p_freefcall(&req->lr_resp);
442
443
free(req);
444
}
445
446
/*
447
* This allows a caller to iterate through the data in a
448
* read or write request (creating the data if packing,
449
* scanning through it if unpacking). This is used for
450
* writing readdir entries, so mode should be L9P_PACK
451
* (but we allow L9P_UNPACK so that debug code can also scan
452
* through the data later, if desired).
453
*
454
* This relies on the Tread op having positioned the request's
455
* iov to the beginning of the data buffer (note the l9p_seek_iov
456
* in l9p_dispatch_tread).
457
*/
458
void
459
l9p_init_msg(struct l9p_message *msg, struct l9p_request *req,
460
enum l9p_pack_mode mode)
461
{
462
463
msg->lm_size = 0;
464
msg->lm_mode = mode;
465
msg->lm_cursor_iov = 0;
466
msg->lm_cursor_offset = 0;
467
msg->lm_niov = req->lr_data_niov;
468
memcpy(msg->lm_iov, req->lr_data_iov,
469
sizeof (struct iovec) * req->lr_data_niov);
470
}
471
472
enum fid_lookup_flags {
473
F_REQUIRE_OPEN = 0x01, /* require that the file be marked OPEN */
474
F_REQUIRE_DIR = 0x02, /* require that the file be marked ISDIR */
475
F_REQUIRE_XATTR = 0x04, /* require that the file be marked XATTR */
476
F_REQUIRE_AUTH = 0x08, /* require that the fid be marked AUTH */
477
F_FORBID_OPEN = 0x10, /* forbid that the file be marked OPEN */
478
F_FORBID_DIR = 0x20, /* forbid that the file be marked ISDIR */
479
F_FORBID_XATTR = 0x40, /* forbid that the file be marked XATTR */
480
F_ALLOW_AUTH = 0x80, /* allow that the fid be marked AUTH */
481
};
482
483
/*
484
* Look up a fid. It must correspond to a valid file, else we return
485
* the given errno (some "not a valid fid" calls must return EIO and
486
* some must return EINVAL and qemu returns ENOENT in other cases and
487
* so on, so we just provide a general "return this error number").
488
*
489
* Callers may also set constraints: fid must be (or not be) open,
490
* must be (or not be) a directory, must be (or not be) an xattr.
491
*
492
* Only one op has a fid that *must* be an auth fid. Most ops forbid
493
* auth fids So instead of FORBID we have ALLOW here and the default
494
* is FORBID.
495
*/
496
static inline int
497
fid_lookup(struct l9p_connection *conn, uint32_t fid, int err, int flags,
498
struct l9p_fid **afile)
499
{
500
struct l9p_fid *file;
501
502
file = ht_find(&conn->lc_files, fid);
503
if (file == NULL)
504
return (err);
505
506
/*
507
* As soon as we go multithreaded / async, this
508
* assert has to become "return EINVAL" or "return err".
509
*
510
* We may also need a way to mark a fid as
511
* "in async op" (valid for some purposes, but cannot be
512
* used elsewhere until async op is completed or aborted).
513
*
514
* For now, this serves for bug-detecting.
515
*/
516
assert(l9p_fid_isvalid(file));
517
518
/*
519
* Note that we're inline expanded and flags is constant,
520
* so unnecessary tests just drop out entirely.
521
*/
522
if ((flags & F_REQUIRE_OPEN) && !l9p_fid_isopen(file))
523
return (EINVAL);
524
if ((flags & F_FORBID_OPEN) && l9p_fid_isopen(file))
525
return (EINVAL);
526
if ((flags & F_REQUIRE_DIR) && !l9p_fid_isdir(file))
527
return (ENOTDIR);
528
if ((flags & F_FORBID_DIR) && l9p_fid_isdir(file))
529
return (EISDIR);
530
if ((flags & F_REQUIRE_XATTR) && !l9p_fid_isxattr(file))
531
return (EINVAL);
532
if ((flags & F_FORBID_XATTR) && l9p_fid_isxattr(file))
533
return (EINVAL);
534
if (l9p_fid_isauth(file)) {
535
if ((flags & (F_REQUIRE_AUTH | F_ALLOW_AUTH)) == 0)
536
return (EINVAL);
537
} else if (flags & F_REQUIRE_AUTH)
538
return (EINVAL);
539
*afile = file;
540
return (0);
541
}
542
543
/*
544
* Append variable-size stat object and adjust io count.
545
* Returns 0 if the entire stat object was packed, -1 if not.
546
* A fully packed object updates the request's io count.
547
*
548
* Caller must use their own private l9p_message object since
549
* a partially packed object will leave the message object in
550
* a useless state.
551
*
552
* Frees the stat object.
553
*/
554
int
555
l9p_pack_stat(struct l9p_message *msg, struct l9p_request *req,
556
struct l9p_stat *st)
557
{
558
struct l9p_connection *conn = req->lr_conn;
559
uint16_t size = l9p_sizeof_stat(st, conn->lc_version);
560
int ret = 0;
561
562
assert(msg->lm_mode == L9P_PACK);
563
564
if (req->lr_resp.io.count + size > req->lr_req.io.count ||
565
l9p_pustat(msg, st, conn->lc_version) < 0)
566
ret = -1;
567
else
568
req->lr_resp.io.count += size;
569
l9p_freestat(st);
570
return (ret);
571
}
572
573
static int
574
l9p_dispatch_tversion(struct l9p_request *req)
575
{
576
struct l9p_connection *conn = req->lr_conn;
577
struct l9p_server *server = conn->lc_server;
578
enum l9p_version remote_version = L9P_INVALID_VERSION;
579
size_t i;
580
const char *remote_version_name;
581
582
for (i = 0; i < N(l9p_versions); i++) {
583
if (strcmp(req->lr_req.version.version,
584
l9p_versions[i].name) == 0) {
585
remote_version = (enum l9p_version)i;
586
break;
587
}
588
}
589
590
if (remote_version == L9P_INVALID_VERSION) {
591
L9P_LOG(L9P_ERROR, "unsupported remote version: %s",
592
req->lr_req.version.version);
593
return (ENOSYS);
594
}
595
596
remote_version_name = l9p_versions[remote_version].name;
597
L9P_LOG(L9P_INFO, "remote version: %s", remote_version_name);
598
L9P_LOG(L9P_INFO, "local version: %s",
599
l9p_versions[server->ls_max_version].name);
600
601
conn->lc_version = MIN(remote_version, server->ls_max_version);
602
conn->lc_msize = MIN(req->lr_req.version.msize, conn->lc_msize);
603
conn->lc_max_io_size = conn->lc_msize - 24;
604
req->lr_resp.version.version = strdup(remote_version_name);
605
req->lr_resp.version.msize = conn->lc_msize;
606
return (0);
607
}
608
609
static int
610
l9p_dispatch_tattach(struct l9p_request *req)
611
{
612
struct l9p_connection *conn = req->lr_conn;
613
struct l9p_backend *be;
614
struct l9p_fid *fid;
615
int error;
616
617
/*
618
* We still don't have Tauth yet, but let's code this part
619
* anyway.
620
*
621
* Look up the auth fid first since if it fails we can just
622
* return immediately.
623
*/
624
if (req->lr_req.tattach.afid != L9P_NOFID) {
625
error = fid_lookup(conn, req->lr_req.tattach.afid, EINVAL,
626
F_REQUIRE_AUTH, &req->lr_fid2);
627
if (error)
628
return (error);
629
} else
630
req->lr_fid2 = NULL;
631
632
fid = l9p_connection_alloc_fid(conn, req->lr_req.hdr.fid);
633
if (fid == NULL)
634
return (EINVAL);
635
636
be = conn->lc_server->ls_backend;
637
638
req->lr_fid = fid;
639
640
/* For backend convenience, set NONUNAME on 9P2000. */
641
if (conn->lc_version == L9P_2000)
642
req->lr_req.tattach.n_uname = L9P_NONUNAME;
643
error = be->attach(be->softc, req);
644
645
/*
646
* On success, fid becomes valid; on failure, disconnect.
647
* It certainly *should* be a directory here...
648
*/
649
if (error == 0) {
650
l9p_fid_setvalid(fid);
651
if (req->lr_resp.rattach.qid.type & L9P_QTDIR)
652
l9p_fid_setdir(fid);
653
} else
654
l9p_connection_remove_fid(conn, fid);
655
return (error);
656
}
657
658
static int
659
l9p_dispatch_tclunk(struct l9p_request *req)
660
{
661
struct l9p_connection *conn = req->lr_conn;
662
struct l9p_backend *be;
663
struct l9p_fid *fid;
664
int error;
665
666
/* Note that clunk is the only way to dispose of an auth fid. */
667
error = fid_lookup(conn, req->lr_req.hdr.fid, ENOENT,
668
F_ALLOW_AUTH, &fid);
669
if (error)
670
return (error);
671
672
be = conn->lc_server->ls_backend;
673
l9p_fid_unsetvalid(fid);
674
675
/*
676
* If it's an xattr fid there must, by definition, be an
677
* xattrclunk. The xattrclunk function can only be NULL if
678
* xattrwalk and xattrcreate are NULL or always return error.
679
*
680
* Q: do we want to allow async xattrclunk in case of very
681
* large xattr create? This will make things difficult,
682
* so probably not.
683
*/
684
if (l9p_fid_isxattr(fid))
685
error = be->xattrclunk(be->softc, fid);
686
else
687
error = be->clunk(be->softc, fid);
688
689
/* fid is now gone regardless of any error return */
690
l9p_connection_remove_fid(conn, fid);
691
return (error);
692
}
693
694
static int
695
l9p_dispatch_tcreate(struct l9p_request *req)
696
{
697
struct l9p_connection *conn = req->lr_conn;
698
struct l9p_backend *be;
699
uint32_t dmperm;
700
int error;
701
702
/* Incoming fid must represent a directory that has not been opened. */
703
error = fid_lookup(conn, req->lr_req.hdr.fid, EINVAL,
704
F_REQUIRE_DIR | F_FORBID_OPEN, &req->lr_fid);
705
if (error)
706
return (error);
707
708
be = conn->lc_server->ls_backend;
709
dmperm = req->lr_req.tcreate.perm;
710
#define MKDIR_OR_SIMILAR \
711
(L9P_DMDIR | L9P_DMSYMLINK | L9P_DMNAMEDPIPE | L9P_DMSOCKET | L9P_DMDEVICE)
712
713
/*
714
* TODO:
715
* - check new file name
716
* - break out different kinds of create (file vs mkdir etc)
717
* - add async file-create (leaves req->lr_fid in limbo)
718
*
719
* A successful file-create changes the fid into an open file.
720
*/
721
error = be->create(be->softc, req);
722
if (error == 0 && (dmperm & MKDIR_OR_SIMILAR) == 0) {
723
l9p_fid_unsetdir(req->lr_fid);
724
l9p_fid_setopen(req->lr_fid);
725
}
726
727
return (error);
728
}
729
730
static int
731
l9p_dispatch_topen(struct l9p_request *req)
732
{
733
struct l9p_connection *conn = req->lr_conn;
734
struct l9p_backend *be;
735
int error;
736
737
error = fid_lookup(conn, req->lr_req.hdr.fid, ENOENT,
738
F_FORBID_OPEN | F_FORBID_XATTR, &req->lr_fid);
739
if (error)
740
return (error);
741
742
be = conn->lc_server->ls_backend;
743
744
/*
745
* TODO:
746
* - add async open (leaves req->lr_fid in limbo)
747
*/
748
error = be->open(be->softc, req);
749
if (error == 0)
750
l9p_fid_setopen(req->lr_fid);
751
return (error);
752
}
753
754
static int
755
l9p_dispatch_tread(struct l9p_request *req)
756
{
757
struct l9p_connection *conn = req->lr_conn;
758
struct l9p_backend *be;
759
struct l9p_fid *fid;
760
int error;
761
762
/* Xattr fids are not open, so we need our own tests. */
763
error = fid_lookup(conn, req->lr_req.hdr.fid, EINVAL, 0, &req->lr_fid);
764
if (error)
765
return (error);
766
767
/*
768
* Adjust so that writing messages (packing data) starts
769
* right after the count field in the response.
770
*
771
* size[4] + Rread[1] + tag[2] + count[4] = 11
772
*/
773
l9p_seek_iov(req->lr_resp_msg.lm_iov, req->lr_resp_msg.lm_niov,
774
req->lr_data_iov, &req->lr_data_niov, 11);
775
776
/*
777
* If it's an xattr fid there must, by definition, be an
778
* xattrread. The xattrread function can only be NULL if
779
* xattrwalk and xattrcreate are NULL or always return error.
780
*
781
* TODO:
782
* separate out directory-read
783
* allow async read
784
*/
785
be = conn->lc_server->ls_backend;
786
fid = req->lr_fid;
787
if (l9p_fid_isxattr(fid)) {
788
error = be->xattrread(be->softc, req);
789
} else if (l9p_fid_isopen(fid)) {
790
error = be->read(be->softc, req);
791
} else {
792
error = EINVAL;
793
}
794
795
return (error);
796
}
797
798
static int
799
l9p_dispatch_tremove(struct l9p_request *req)
800
{
801
struct l9p_connection *conn = req->lr_conn;
802
struct l9p_backend *be;
803
struct l9p_fid *fid;
804
int error;
805
806
/*
807
* ?? Should we allow Tremove on auth fids? If so, do
808
* we pretend it is just a Tclunk?
809
*/
810
error = fid_lookup(conn, req->lr_req.hdr.fid, EINVAL, 0, &fid);
811
if (error)
812
return (error);
813
814
be = conn->lc_server->ls_backend;
815
l9p_fid_unsetvalid(fid);
816
817
error = be->remove(be->softc, fid);
818
/* fid is now gone regardless of any error return */
819
l9p_connection_remove_fid(conn, fid);
820
return (error);
821
}
822
823
static int
824
l9p_dispatch_tstat(struct l9p_request *req)
825
{
826
struct l9p_connection *conn = req->lr_conn;
827
struct l9p_backend *be;
828
struct l9p_fid *fid;
829
int error;
830
831
/* Allow Tstat on auth fid? Seems harmless enough... */
832
error = fid_lookup(conn, req->lr_req.hdr.fid, ENOENT,
833
F_ALLOW_AUTH, &fid);
834
if (error)
835
return (error);
836
837
be = conn->lc_server->ls_backend;
838
req->lr_fid = fid;
839
error = be->stat(be->softc, req);
840
841
if (error == 0) {
842
if (l9p_fid_isauth(fid))
843
req->lr_resp.rstat.stat.qid.type |= L9P_QTAUTH;
844
845
/* should we check req->lr_resp.rstat.qid.type L9P_QTDIR bit? */
846
if (req->lr_resp.rstat.stat.qid.type &= L9P_QTDIR)
847
l9p_fid_setdir(fid);
848
else
849
l9p_fid_unsetdir(fid);
850
}
851
852
return (error);
853
}
854
855
static int
856
l9p_dispatch_twalk(struct l9p_request *req)
857
{
858
struct l9p_connection *conn = req->lr_conn;
859
struct l9p_backend *be;
860
struct l9p_fid *fid, *newfid;
861
uint16_t n;
862
int error;
863
864
/* Can forbid XATTR, but cannot require DIR. */
865
error = fid_lookup(conn, req->lr_req.hdr.fid, ENOENT,
866
F_FORBID_XATTR, &fid);
867
if (error)
868
return (error);
869
870
if (req->lr_req.twalk.hdr.fid != req->lr_req.twalk.newfid) {
871
newfid = l9p_connection_alloc_fid(conn,
872
req->lr_req.twalk.newfid);
873
if (newfid == NULL)
874
return (EINVAL);
875
} else
876
newfid = fid;
877
878
be = conn->lc_server->ls_backend;
879
req->lr_fid = fid;
880
req->lr_newfid = newfid;
881
error = be->walk(be->softc, req);
882
883
/*
884
* If newfid == fid, then fid itself has (potentially) changed,
885
* but is still valid. Otherwise set newfid valid on
886
* success, and destroy it on error.
887
*/
888
if (newfid != fid) {
889
if (error == 0)
890
l9p_fid_setvalid(newfid);
891
else
892
l9p_connection_remove_fid(conn, newfid);
893
}
894
895
/*
896
* If we walked any name elements, the last (n-1'th) qid
897
* has the type (dir vs file) for the new fid. Otherwise
898
* the type of newfid is the same as fid. Of course, if
899
* n==0 and fid==newfid, fid is already set up correctly
900
* as the whole thing was a big no-op, but it's safe to
901
* copy its dir bit to itself.
902
*/
903
if (error == 0) {
904
n = req->lr_resp.rwalk.nwqid;
905
if (n > 0) {
906
if (req->lr_resp.rwalk.wqid[n - 1].type & L9P_QTDIR)
907
l9p_fid_setdir(newfid);
908
} else {
909
if (l9p_fid_isdir(fid))
910
l9p_fid_setdir(newfid);
911
}
912
}
913
return (error);
914
}
915
916
static int
917
l9p_dispatch_twrite(struct l9p_request *req)
918
{
919
struct l9p_connection *conn = req->lr_conn;
920
struct l9p_backend *be;
921
struct l9p_fid *fid;
922
int error;
923
924
/* Cannot require open due to xattr write, but can forbid dir. */
925
error = fid_lookup(conn, req->lr_req.hdr.fid, EINVAL,
926
F_FORBID_DIR, &req->lr_fid);
927
if (error)
928
return (error);
929
930
/*
931
* Adjust to point to the data to be written (a la
932
* l9p_dispatch_tread, but we're pointing into the request
933
* buffer rather than the response):
934
*
935
* size[4] + Twrite[1] + tag[2] + fid[4] + offset[8] + count[4] = 23
936
*/
937
l9p_seek_iov(req->lr_req_msg.lm_iov, req->lr_req_msg.lm_niov,
938
req->lr_data_iov, &req->lr_data_niov, 23);
939
940
/*
941
* Unlike read, write and xattrwrite are optional (for R/O fs).
942
*
943
* TODO:
944
* allow async write
945
*/
946
be = conn->lc_server->ls_backend;
947
fid = req->lr_fid;
948
if (l9p_fid_isxattr(fid)) {
949
error = be->xattrwrite != NULL ?
950
be->xattrwrite(be->softc, req) : ENOSYS;
951
} else if (l9p_fid_isopen(fid)) {
952
error = be->write != NULL ?
953
be->write(be->softc, req) : ENOSYS;
954
} else {
955
error = EINVAL;
956
}
957
958
return (error);
959
}
960
961
static int
962
l9p_dispatch_twstat(struct l9p_request *req)
963
{
964
struct l9p_connection *conn = req->lr_conn;
965
struct l9p_backend *be;
966
int error;
967
968
error = fid_lookup(conn, req->lr_req.hdr.fid, EINVAL,
969
F_FORBID_XATTR, &req->lr_fid);
970
if (error)
971
return (error);
972
973
be = conn->lc_server->ls_backend;
974
error = be->wstat != NULL ? be->wstat(be->softc, req) : ENOSYS;
975
return (error);
976
}
977
978
static int
979
l9p_dispatch_tstatfs(struct l9p_request *req)
980
{
981
struct l9p_connection *conn = req->lr_conn;
982
struct l9p_backend *be;
983
int error;
984
985
/* Should we allow statfs on auth fids? */
986
error = fid_lookup(conn, req->lr_req.hdr.fid, EINVAL, 0, &req->lr_fid);
987
if (error)
988
return (error);
989
990
be = conn->lc_server->ls_backend;
991
error = be->statfs(be->softc, req);
992
return (error);
993
}
994
995
static int
996
l9p_dispatch_tlopen(struct l9p_request *req)
997
{
998
struct l9p_connection *conn = req->lr_conn;
999
struct l9p_backend *be;
1000
int error;
1001
1002
error = fid_lookup(conn, req->lr_req.hdr.fid, ENOENT,
1003
F_FORBID_OPEN | F_FORBID_XATTR, &req->lr_fid);
1004
if (error)
1005
return (error);
1006
1007
be = conn->lc_server->ls_backend;
1008
1009
/*
1010
* TODO:
1011
* - add async open (leaves req->lr_fid in limbo)
1012
*/
1013
error = be->lopen != NULL ? be->lopen(be->softc, req) : ENOSYS;
1014
if (error == 0)
1015
l9p_fid_setopen(req->lr_fid);
1016
return (error);
1017
}
1018
1019
static int
1020
l9p_dispatch_tlcreate(struct l9p_request *req)
1021
{
1022
struct l9p_connection *conn = req->lr_conn;
1023
struct l9p_backend *be;
1024
int error;
1025
1026
error = fid_lookup(conn, req->lr_req.hdr.fid, ENOENT,
1027
F_REQUIRE_DIR | F_FORBID_OPEN, &req->lr_fid);
1028
if (error)
1029
return (error);
1030
1031
be = conn->lc_server->ls_backend;
1032
1033
/*
1034
* TODO:
1035
* - check new file name
1036
* - add async create (leaves req->lr_fid in limbo)
1037
*/
1038
error = be->lcreate != NULL ? be->lcreate(be->softc, req) : ENOSYS;
1039
if (error == 0) {
1040
l9p_fid_unsetdir(req->lr_fid);
1041
l9p_fid_setopen(req->lr_fid);
1042
}
1043
return (error);
1044
}
1045
1046
static int
1047
l9p_dispatch_tsymlink(struct l9p_request *req)
1048
{
1049
struct l9p_connection *conn = req->lr_conn;
1050
struct l9p_backend *be;
1051
int error;
1052
1053
/* This doesn't affect the containing dir; maybe allow OPEN? */
1054
error = fid_lookup(conn, req->lr_req.hdr.fid, ENOENT,
1055
F_REQUIRE_DIR | F_FORBID_OPEN, &req->lr_fid);
1056
if (error)
1057
return (error);
1058
1059
be = conn->lc_server->ls_backend;
1060
1061
/*
1062
* TODO:
1063
* - check new file name
1064
*/
1065
error = be->symlink != NULL ? be->symlink(be->softc, req) : ENOSYS;
1066
return (error);
1067
}
1068
1069
static int
1070
l9p_dispatch_tmknod(struct l9p_request *req)
1071
{
1072
struct l9p_connection *conn = req->lr_conn;
1073
struct l9p_backend *be;
1074
int error;
1075
1076
/* This doesn't affect the containing dir; maybe allow OPEN? */
1077
error = fid_lookup(conn, req->lr_req.hdr.fid, ENOENT,
1078
F_REQUIRE_DIR | F_FORBID_OPEN, &req->lr_fid);
1079
if (error)
1080
return (error);
1081
1082
be = conn->lc_server->ls_backend;
1083
1084
/*
1085
* TODO:
1086
* - check new file name
1087
*/
1088
error = be->mknod != NULL ? be->mknod(be->softc, req) : ENOSYS;
1089
return (error);
1090
}
1091
1092
static int
1093
l9p_dispatch_trename(struct l9p_request *req)
1094
{
1095
struct l9p_connection *conn = req->lr_conn;
1096
struct l9p_backend *be;
1097
int error;
1098
1099
/* Rename directory or file (including symlink etc). */
1100
error = fid_lookup(conn, req->lr_req.hdr.fid, ENOENT,
1101
F_FORBID_XATTR, &req->lr_fid);
1102
if (error)
1103
return (error);
1104
1105
/* Doesn't affect new dir fid; maybe allow OPEN? */
1106
error = fid_lookup(conn, req->lr_req.trename.dfid, ENOENT,
1107
F_REQUIRE_DIR | F_FORBID_OPEN, &req->lr_fid2);
1108
if (error)
1109
return (error);
1110
1111
be = conn->lc_server->ls_backend;
1112
1113
/*
1114
* TODO:
1115
* - check new file name (trename.name)
1116
*/
1117
error = be->rename != NULL ? be->rename(be->softc, req) : ENOSYS;
1118
return (error);
1119
}
1120
1121
static int
1122
l9p_dispatch_treadlink(struct l9p_request *req)
1123
{
1124
struct l9p_connection *conn = req->lr_conn;
1125
struct l9p_backend *be;
1126
int error;
1127
1128
/*
1129
* The underlying readlink will fail unless it's a symlink,
1130
* and the back end has to check, but we might as well forbid
1131
* directories and open files here since it's cheap.
1132
*/
1133
error = fid_lookup(conn, req->lr_req.hdr.fid, ENOENT,
1134
F_FORBID_DIR | F_FORBID_OPEN, &req->lr_fid);
1135
if (error)
1136
return (error);
1137
1138
be = conn->lc_server->ls_backend;
1139
1140
error = be->readlink != NULL ? be->readlink(be->softc, req) : ENOSYS;
1141
return (error);
1142
}
1143
1144
static int
1145
l9p_dispatch_tgetattr(struct l9p_request *req)
1146
{
1147
struct l9p_connection *conn = req->lr_conn;
1148
struct l9p_backend *be;
1149
int error;
1150
1151
error = fid_lookup(conn, req->lr_req.hdr.fid, ENOENT,
1152
F_FORBID_XATTR, &req->lr_fid);
1153
if (error)
1154
return (error);
1155
1156
be = conn->lc_server->ls_backend;
1157
1158
error = be->getattr != NULL ? be->getattr(be->softc, req) : ENOSYS;
1159
return (error);
1160
}
1161
1162
static int
1163
l9p_dispatch_tsetattr(struct l9p_request *req)
1164
{
1165
struct l9p_connection *conn = req->lr_conn;
1166
struct l9p_backend *be;
1167
int error;
1168
1169
error = fid_lookup(conn, req->lr_req.hdr.fid, ENOENT,
1170
F_FORBID_XATTR, &req->lr_fid);
1171
if (error)
1172
return (error);
1173
1174
be = conn->lc_server->ls_backend;
1175
1176
error = be->setattr != NULL ? be->setattr(be->softc, req) : ENOSYS;
1177
return (error);
1178
}
1179
1180
static int
1181
l9p_dispatch_txattrwalk(struct l9p_request *req)
1182
{
1183
struct l9p_connection *conn = req->lr_conn;
1184
struct l9p_backend *be;
1185
struct l9p_fid *fid, *newfid;
1186
int error;
1187
1188
/*
1189
* Not sure if we care if file-or-dir is open or not.
1190
* However, the fid argument should always be a file or
1191
* dir and the newfid argument must be supplied, must
1192
* be different, and always becomes a new xattr,
1193
* so this is not very much like Twalk.
1194
*/
1195
error = fid_lookup(conn, req->lr_req.hdr.fid, ENOENT,
1196
F_FORBID_XATTR, &fid);
1197
if (error)
1198
return (error);
1199
1200
newfid = l9p_connection_alloc_fid(conn, req->lr_req.txattrwalk.newfid);
1201
if (newfid == NULL)
1202
return (EINVAL);
1203
1204
be = conn->lc_server->ls_backend;
1205
1206
req->lr_fid = fid;
1207
req->lr_newfid = newfid;
1208
error = be->xattrwalk != NULL ? be->xattrwalk(be->softc, req) : ENOSYS;
1209
1210
/*
1211
* Success/fail is similar to Twalk, except that we need
1212
* to set the xattr type bit in the new fid. It's also
1213
* much simpler since newfid is always a new fid.
1214
*/
1215
if (error == 0) {
1216
l9p_fid_setvalid(newfid);
1217
l9p_fid_setxattr(newfid);
1218
} else {
1219
l9p_connection_remove_fid(conn, newfid);
1220
}
1221
return (error);
1222
}
1223
1224
static int
1225
l9p_dispatch_txattrcreate(struct l9p_request *req)
1226
{
1227
struct l9p_connection *conn = req->lr_conn;
1228
struct l9p_backend *be;
1229
struct l9p_fid *fid;
1230
int error;
1231
1232
/*
1233
* Forbid incoming open fid since it's going to become an
1234
* xattr fid instead. If it turns out we need to allow
1235
* it, fs code will need to handle this.
1236
*
1237
* Curiously, qemu 9pfs uses ENOENT for a bad txattrwalk
1238
* fid, but EINVAL for txattrcreate (so we do too).
1239
*/
1240
error = fid_lookup(conn, req->lr_req.hdr.fid, EINVAL,
1241
F_FORBID_XATTR | F_FORBID_OPEN, &fid);
1242
if (error)
1243
return (error);
1244
1245
be = conn->lc_server->ls_backend;
1246
1247
req->lr_fid = fid;
1248
error = be->xattrcreate != NULL ? be->xattrcreate(be->softc, req) :
1249
ENOSYS;
1250
1251
/*
1252
* On success, fid has changed from a regular (file or dir)
1253
* fid to an xattr fid.
1254
*/
1255
if (error == 0) {
1256
l9p_fid_unsetdir(fid);
1257
l9p_fid_setxattr(fid);
1258
}
1259
return (error);
1260
}
1261
1262
static int
1263
l9p_dispatch_treaddir(struct l9p_request *req)
1264
{
1265
struct l9p_connection *conn = req->lr_conn;
1266
struct l9p_backend *be;
1267
int error;
1268
1269
error = fid_lookup(conn, req->lr_req.hdr.fid, ENOENT,
1270
F_REQUIRE_DIR | F_REQUIRE_OPEN, &req->lr_fid);
1271
if (error)
1272
return (error);
1273
1274
/*
1275
* Adjust so that writing messages (packing data) starts
1276
* right after the count field in the response.
1277
*
1278
* size[4] + Rreaddir[1] + tag[2] + count[4] = 11
1279
*/
1280
l9p_seek_iov(req->lr_resp_msg.lm_iov, req->lr_resp_msg.lm_niov,
1281
req->lr_data_iov, &req->lr_data_niov, 11);
1282
1283
be = conn->lc_server->ls_backend;
1284
1285
error = be->readdir != NULL ? be->readdir(be->softc, req) : ENOSYS;
1286
return (error);
1287
}
1288
1289
static int
1290
l9p_dispatch_tfsync(struct l9p_request *req)
1291
{
1292
struct l9p_connection *conn = req->lr_conn;
1293
struct l9p_backend *be;
1294
int error;
1295
1296
error = fid_lookup(conn, req->lr_req.hdr.fid, ENOENT,
1297
F_REQUIRE_OPEN, &req->lr_fid);
1298
if (error)
1299
return (error);
1300
1301
be = conn->lc_server->ls_backend;
1302
1303
error = be->fsync != NULL ? be->fsync(be->softc, req) : ENOSYS;
1304
return (error);
1305
}
1306
1307
static int
1308
l9p_dispatch_tlock(struct l9p_request *req)
1309
{
1310
struct l9p_connection *conn = req->lr_conn;
1311
struct l9p_backend *be;
1312
int error;
1313
1314
/* Forbid directories? */
1315
error = fid_lookup(conn, req->lr_req.hdr.fid, ENOENT,
1316
F_REQUIRE_OPEN, &req->lr_fid);
1317
if (error)
1318
return (error);
1319
1320
be = conn->lc_server->ls_backend;
1321
1322
/*
1323
* TODO: multiple client handling; perhaps async locking.
1324
*/
1325
error = be->lock != NULL ? be->lock(be->softc, req) : ENOSYS;
1326
return (error);
1327
}
1328
1329
static int
1330
l9p_dispatch_tgetlock(struct l9p_request *req)
1331
{
1332
struct l9p_connection *conn = req->lr_conn;
1333
struct l9p_backend *be;
1334
int error;
1335
1336
error = fid_lookup(conn, req->lr_req.hdr.fid, ENOENT,
1337
F_REQUIRE_OPEN, &req->lr_fid);
1338
if (error)
1339
return (error);
1340
1341
be = conn->lc_server->ls_backend;
1342
1343
/*
1344
* TODO: multiple client handling; perhaps async locking.
1345
*/
1346
error = be->getlock != NULL ? be->getlock(be->softc, req) : ENOSYS;
1347
return (error);
1348
}
1349
1350
static int
1351
l9p_dispatch_tlink(struct l9p_request *req)
1352
{
1353
struct l9p_connection *conn = req->lr_conn;
1354
struct l9p_backend *be;
1355
int error;
1356
1357
/*
1358
* Note, dfid goes into fid2 in current scheme.
1359
*
1360
* Allow open dir? Target dir fid is not modified...
1361
*/
1362
error = fid_lookup(conn, req->lr_req.tlink.dfid, ENOENT,
1363
F_REQUIRE_DIR | F_FORBID_OPEN, &req->lr_fid2);
1364
if (error)
1365
return (error);
1366
1367
error = fid_lookup(conn, req->lr_req.hdr.fid, ENOENT,
1368
F_FORBID_DIR | F_FORBID_XATTR, &req->lr_fid);
1369
if (error)
1370
return (error);
1371
1372
be = conn->lc_server->ls_backend;
1373
1374
error = be->link != NULL ? be->link(be->softc, req) : ENOSYS;
1375
return (error);
1376
}
1377
1378
static int
1379
l9p_dispatch_tmkdir(struct l9p_request *req)
1380
{
1381
struct l9p_connection *conn = req->lr_conn;
1382
struct l9p_backend *be;
1383
int error;
1384
1385
error = fid_lookup(conn, req->lr_req.hdr.fid, ENOENT,
1386
F_REQUIRE_DIR | F_FORBID_OPEN, &req->lr_fid);
1387
if (error)
1388
return (error);
1389
1390
/* Slashes embedded in the name are not allowed */
1391
if (strchr(req->lr_req.tlcreate.name, '/') != NULL)
1392
return (EINVAL);
1393
1394
be = conn->lc_server->ls_backend;
1395
error = be->mkdir != NULL ? be->mkdir(be->softc, req) : ENOSYS;
1396
return (error);
1397
}
1398
1399
static int
1400
l9p_dispatch_trenameat(struct l9p_request *req)
1401
{
1402
struct l9p_connection *conn = req->lr_conn;
1403
struct l9p_backend *be;
1404
int error;
1405
1406
error = fid_lookup(conn, req->lr_req.hdr.fid, ENOENT,
1407
F_REQUIRE_DIR | F_FORBID_OPEN, &req->lr_fid);
1408
if (error)
1409
return (error);
1410
1411
error = fid_lookup(conn, req->lr_req.trenameat.newdirfid, ENOENT,
1412
F_REQUIRE_DIR | F_FORBID_OPEN, &req->lr_fid2);
1413
if (error)
1414
return (error);
1415
1416
be = conn->lc_server->ls_backend;
1417
1418
/* TODO: check old and new names */
1419
error = be->renameat != NULL ? be->renameat(be->softc, req) : ENOSYS;
1420
return (error);
1421
}
1422
1423
static int
1424
l9p_dispatch_tunlinkat(struct l9p_request *req)
1425
{
1426
struct l9p_connection *conn = req->lr_conn;
1427
struct l9p_backend *be;
1428
int error;
1429
1430
error = fid_lookup(conn, req->lr_req.hdr.fid, ENOENT,
1431
F_REQUIRE_DIR | F_FORBID_OPEN, &req->lr_fid);
1432
if (error)
1433
return (error);
1434
1435
be = conn->lc_server->ls_backend;
1436
1437
/* TODO: check dir-or-file name */
1438
error = be->unlinkat != NULL ? be->unlinkat(be->softc, req) : ENOSYS;
1439
return (error);
1440
}
1441
1442