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 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