1 /*
2 * Copyright 2016 Jakub Klama <jceel@FreeBSD.org>
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
l9p_dispatch_request(struct l9p_request * req)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
e29p(int errnum)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
e2linux(int errnum)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
l9p_respond(struct l9p_request * req,bool drop,bool rmtag)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
l9p_init_msg(struct l9p_message * msg,struct l9p_request * req,enum l9p_pack_mode mode)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
fid_lookup(struct l9p_connection * conn,uint32_t fid,int err,int flags,struct l9p_fid ** afile)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
l9p_pack_stat(struct l9p_message * msg,struct l9p_request * req,struct l9p_stat * st)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
l9p_dispatch_tversion(struct l9p_request * req)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
l9p_dispatch_tattach(struct l9p_request * req)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
l9p_dispatch_tclunk(struct l9p_request * req)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
l9p_dispatch_tcreate(struct l9p_request * req)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
l9p_dispatch_topen(struct l9p_request * req)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
l9p_dispatch_tread(struct l9p_request * req)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
l9p_dispatch_tremove(struct l9p_request * req)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
l9p_dispatch_tstat(struct l9p_request * req)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
l9p_dispatch_twalk(struct l9p_request * req)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
l9p_dispatch_twrite(struct l9p_request * req)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
l9p_dispatch_twstat(struct l9p_request * req)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
l9p_dispatch_tstatfs(struct l9p_request * req)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
l9p_dispatch_tlopen(struct l9p_request * req)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
l9p_dispatch_tlcreate(struct l9p_request * req)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
l9p_dispatch_tsymlink(struct l9p_request * req)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
l9p_dispatch_tmknod(struct l9p_request * req)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
l9p_dispatch_trename(struct l9p_request * req)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
l9p_dispatch_treadlink(struct l9p_request * req)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
l9p_dispatch_tgetattr(struct l9p_request * req)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
l9p_dispatch_tsetattr(struct l9p_request * req)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
l9p_dispatch_txattrwalk(struct l9p_request * req)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
l9p_dispatch_txattrcreate(struct l9p_request * req)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
l9p_dispatch_treaddir(struct l9p_request * req)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
l9p_dispatch_tfsync(struct l9p_request * req)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
l9p_dispatch_tlock(struct l9p_request * req)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
l9p_dispatch_tgetlock(struct l9p_request * req)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
l9p_dispatch_tlink(struct l9p_request * req)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
l9p_dispatch_tmkdir(struct l9p_request * req)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
l9p_dispatch_trenameat(struct l9p_request * req)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
l9p_dispatch_tunlinkat(struct l9p_request * req)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