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