2 * Copyright 2016 Jakub Klama <jceel@FreeBSD.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted providing that the following conditions
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.
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.
29 * Based on libixp code: ©2007-2010 Kris Maglione <maglione.k at Gmail>
39 #include <sys/types.h>
41 #include <sys/mount.h>
42 #include <sys/param.h>
43 #include <sys/queue.h>
44 #include <sys/socket.h>
52 #include "../lib9p_impl.h"
55 #include "../rfuncs.h"
56 #include "../genacl.h"
60 #if defined(WITH_CASPER)
61 #include <libcasper.h>
62 #include <casper/cap_pwd.h>
63 #include <casper/cap_grp.h>
66 #if defined(__FreeBSD__)
67 #include <sys/param.h>
68 #if __FreeBSD_version >= 1000000
73 #if defined(__FreeBSD__)
74 #define HAVE_BIRTHTIME
77 #if defined(__APPLE__)
78 #include <sys/syscall.h>
79 #include "Availability.h"
80 #define ACL_TYPE_NFS4 ACL_TYPE_EXTENDED
86 #if defined(WITH_CASPER)
87 cap_channel_t *fs_cappwd;
88 cap_channel_t *fs_capgrp;
98 struct fs_authinfo *ff_ai;
99 pthread_mutex_t ff_mtx;
100 struct l9p_acl *ff_acl; /* cached ACL if any */
103 #define FF_NO_NFSV4_ACL 0x01 /* don't go looking for NFSv4 ACLs */
104 /* FF_NO_POSIX_ACL 0x02 -- not yet */
107 * Our authinfo consists of:
109 * - a reference count
113 * The "default" gid is the first gid in the git-set, provided the
114 * set size is at least 1. The set-size may be zero, though.
116 * Adjustments to the ref-count must be atomic, once it's shared.
117 * It would be nice to use C11 atomics here but they are not common
118 * enough to all systems just yet; for now, we use a mutex.
120 * Note that some ops (Linux style ones) pass an effective gid for
121 * the op, in which case, that gid may override. To achieve this
122 * effect, permissions testing functions also take an extra gid.
123 * If this gid is (gid_t)-1 it is not used and only the remaining
126 * The uid may also be (uid_t)-1, meaning "no uid was available
127 * at all at attach time". In this case, new files inherit parent
130 * The refcount is simply the number of "openfile"s using this
131 * authinfo (so that when the last ref goes away, we can free it).
133 * There are also master ACL flags (same as in ff_flags).
136 pthread_mutex_t ai_mtx; /* lock for refcnt */
141 gid_t ai_gids[]; /* NB: flexible array member */
145 * We have a global-static mutex for single-threading Tattach
146 * requests, which use getpwnam (and indirectly, getgr* functions)
147 * which are not reentrant.
149 static bool fs_attach_mutex_inited;
150 static pthread_mutex_t fs_attach_mutex;
153 * Internal functions (except inline functions).
155 static struct passwd *fs_getpwuid(struct fs_softc *, uid_t, struct r_pgdata *);
156 static struct group *fs_getgrgid(struct fs_softc *, gid_t, struct r_pgdata *);
157 static int fs_buildname(struct l9p_fid *, char *, char *, size_t);
158 static int fs_pdir(struct fs_softc *, struct l9p_fid *, char *, size_t,
160 static int fs_dpf(char *, char *, size_t);
161 static int fs_oflags_dotu(int, int *);
162 static int fs_oflags_dotl(uint32_t, int *, enum l9p_omode *);
163 static int fs_nde(struct fs_softc *, struct l9p_fid *, bool, gid_t,
164 struct stat *, uid_t *, gid_t *);
165 static struct fs_fid *open_fid(int, const char *, struct fs_authinfo *, bool);
166 static void dostat(struct fs_softc *, struct l9p_stat *, char *,
167 struct stat *, bool dotu);
168 static void dostatfs(struct l9p_statfs *, struct statfs *, long);
169 static void fillacl(struct fs_fid *ff);
170 static struct l9p_acl *getacl(struct fs_fid *ff, int fd, const char *path);
171 static void dropacl(struct fs_fid *ff);
172 static struct l9p_acl *look_for_nfsv4_acl(struct fs_fid *ff, int fd,
174 static int check_access(int32_t,
175 struct l9p_acl *, struct stat *, struct l9p_acl *, struct stat *,
176 struct fs_authinfo *, gid_t);
177 static void generate_qid(struct stat *, struct l9p_qid *);
179 static int fs_icreate(void *, struct l9p_fid *, char *, int,
180 bool, mode_t, gid_t, struct stat *);
181 static int fs_iopen(void *, struct l9p_fid *, int, enum l9p_omode,
182 gid_t, struct stat *);
183 static int fs_imkdir(void *, struct l9p_fid *, char *,
184 bool, mode_t, gid_t, struct stat *);
185 static int fs_imkfifo(void *, struct l9p_fid *, char *,
186 bool, mode_t, gid_t, struct stat *);
187 static int fs_imknod(void *, struct l9p_fid *, char *,
188 bool, mode_t, dev_t, gid_t, struct stat *);
189 static int fs_imksocket(void *, struct l9p_fid *, char *,
190 bool, mode_t, gid_t, struct stat *);
191 static int fs_isymlink(void *, struct l9p_fid *, char *, char *,
192 gid_t, struct stat *);
195 * Internal functions implementing backend.
197 static int fs_attach(void *, struct l9p_request *);
198 static int fs_clunk(void *, struct l9p_fid *);
199 static int fs_create(void *, struct l9p_request *);
200 static int fs_open(void *, struct l9p_request *);
201 static int fs_read(void *, struct l9p_request *);
202 static int fs_remove(void *, struct l9p_fid *);
203 static int fs_stat(void *, struct l9p_request *);
204 static int fs_walk(void *, struct l9p_request *);
205 static int fs_write(void *, struct l9p_request *);
206 static int fs_wstat(void *, struct l9p_request *);
207 static int fs_statfs(void *, struct l9p_request *);
208 static int fs_lopen(void *, struct l9p_request *);
209 static int fs_lcreate(void *, struct l9p_request *);
210 static int fs_symlink(void *, struct l9p_request *);
211 static int fs_mknod(void *, struct l9p_request *);
212 static int fs_rename(void *, struct l9p_request *);
213 static int fs_readlink(void *, struct l9p_request *);
214 static int fs_getattr(void *, struct l9p_request *);
215 static int fs_setattr(void *, struct l9p_request *);
216 static int fs_xattrwalk(void *, struct l9p_request *);
217 static int fs_xattrcreate(void *, struct l9p_request *);
218 static int fs_readdir(void *, struct l9p_request *);
219 static int fs_fsync(void *, struct l9p_request *);
220 static int fs_lock(void *, struct l9p_request *);
221 static int fs_getlock(void *, struct l9p_request *);
222 static int fs_link(void *, struct l9p_request *);
223 static int fs_renameat(void *, struct l9p_request *);
224 static int fs_unlinkat(void *, struct l9p_request *);
225 static void fs_freefid(void *, struct l9p_fid *);
228 * Convert from 9p2000 open/create mode to Unix-style O_* flags.
229 * This includes 9p2000.u extensions, but not 9p2000.L protocol,
230 * which has entirely different open, create, etc., flag bits.
232 * The <mode> given here is the one-byte (uint8_t) "mode"
233 * argument to Tcreate or Topen, so it can have at most 8 bits.
235 * https://swtch.com/plan9port/man/man9/open.html and
236 * http://plan9.bell-labs.com/magic/man2html/5/open
239 * The [low two bits of the] mode field determines the
240 * type of I/O ... [I]f mode has the OTRUNC (0x10) bit
241 * set, the file is to be truncated, which requires write
242 * permission ...; if the mode has the ORCLOSE (0x40) bit
243 * set, the file is to be removed when the fid is clunked,
244 * which requires permission to remove the file from its
245 * directory. All other bits in mode should be zero. It
246 * is illegal to write a directory, truncate it, or
247 * attempt to remove it on close.
249 * 9P2000.u may add ODIRECT (0x80); this is not completely clear.
250 * The fcall.h header defines OCEXEC (0x20) as well, but it makes
251 * no sense to send this to a server. There seem to be no bits
254 * We always turn on O_NOCTTY since as a server, we never want
255 * to gain a controlling terminal. We always turn on O_NOFOLLOW
256 * for reasons described elsewhere.
259 fs_oflags_dotu(int mode, int *aflags)
262 #define CONVERT(theirs, ours) \
264 if (mode & (theirs)) { \
270 switch (mode & L9P_OACCMODE) {
286 if (mode & L9P_OTRUNC)
292 flags |= O_NOCTTY | O_NOFOLLOW;
294 CONVERT(L9P_OTRUNC, O_TRUNC);
297 * Now take away some flags locally:
298 * the access mode (already translated)
299 * ORCLOSE - caller only
300 * OCEXEC - makes no sense in server
301 * ODIRECT - not applicable here
302 * If there are any flag bits left after this,
303 * we were unable to translate them. For now, let's
304 * treat this as EINVAL so that we can catch problems.
306 mode &= ~(L9P_OACCMODE | L9P_ORCLOSE | L9P_OCEXEC | L9P_ODIRECT);
309 "fs_oflags_dotu: untranslated bits: %#x",
320 * Convert from 9P2000.L (Linux) open mode bits to O_* flags.
321 * See fs_oflags_dotu above.
323 * Linux currently does not have open-for-exec, but there is a
324 * proposal for it using O_PATH|O_NOFOLLOW, now handled here.
326 * We may eventually also set L9P_ORCLOSE for L_O_TMPFILE.
329 fs_oflags_dotl(uint32_t l_mode, int *aflags, enum l9p_omode *ap9)
333 #define CLEAR(theirs) l_mode &= ~(uint32_t)(theirs)
334 #define CONVERT(theirs, ours) \
336 if (l_mode & (theirs)) { \
343 * Linux O_RDONLY, O_WRONLY, O_RDWR (0,1,2) match BSD/MacOS.
345 flags = l_mode & O_ACCMODE;
350 if ((l_mode & (L9P_L_O_PATH | L9P_L_O_NOFOLLOW)) ==
351 (L9P_L_O_PATH | L9P_L_O_NOFOLLOW)) {
352 CLEAR(L9P_L_O_PATH | L9P_L_O_NOFOLLOW);
356 * Slightly dirty, but same dirt, really, as
357 * setting flags from l_mode & O_ACCMODE.
359 p9 = (enum l9p_omode)flags; /* slightly dirty */
362 /* turn L_O_TMPFILE into L9P_ORCLOSE in *p9? */
363 if (l_mode & L9P_L_O_TRUNC)
364 p9 |= L9P_OTRUNC; /* but don't CLEAR yet */
366 flags |= O_NOCTTY | O_NOFOLLOW;
369 * L_O_CREAT seems to be noise, since we get separate open
370 * and create. But it is actually set sometimes. We just
371 * throw it out here; create ops must set it themselves and
372 * open ops have no permissions bits and hence cannot create.
374 * L_O_EXCL does make sense on create ops, i.e., we can
375 * take a create op with or without L_O_EXCL. We pass that
378 CLEAR(L9P_L_O_CREAT);
379 CONVERT(L9P_L_O_EXCL, O_EXCL);
380 CONVERT(L9P_L_O_TRUNC, O_TRUNC);
381 CONVERT(L9P_L_O_DIRECTORY, O_DIRECTORY);
382 CONVERT(L9P_L_O_APPEND, O_APPEND);
383 CONVERT(L9P_L_O_NONBLOCK, O_NONBLOCK);
386 * Discard these as useless noise at our (server) end.
387 * (NOATIME might be useful but we can only set it on a
390 CLEAR(L9P_L_O_CLOEXEC);
391 CLEAR(L9P_L_O_DIRECT);
392 CLEAR(L9P_L_O_DSYNC);
393 CLEAR(L9P_L_O_FASYNC);
394 CLEAR(L9P_L_O_LARGEFILE);
395 CLEAR(L9P_L_O_NOATIME);
396 CLEAR(L9P_L_O_NOCTTY);
397 CLEAR(L9P_L_O_NOFOLLOW);
402 "fs_oflags_dotl: untranslated bits: %#x",
414 static struct passwd *
415 fs_getpwuid(struct fs_softc *sc, uid_t uid, struct r_pgdata *pg)
417 #if defined(WITH_CASPER)
418 return (r_cap_getpwuid(sc->fs_cappwd, uid, pg));
421 return (r_getpwuid(uid, pg));
425 static struct group *
426 fs_getgrgid(struct fs_softc *sc, gid_t gid, struct r_pgdata *pg)
428 #if defined(WITH_CASPER)
429 return (r_cap_getgrgid(sc->fs_capgrp, gid, pg));
432 return (r_getgrgid(gid, pg));
437 * Build full name of file by appending given name to directory name.
440 fs_buildname(struct l9p_fid *dir, char *name, char *buf, size_t size)
442 struct fs_fid *dirf = dir->lo_aux;
445 assert(dirf != NULL);
446 dlen = strlen(dirf->ff_name);
447 nlen1 = strlen(name) + 1; /* +1 for '\0' */
448 if (dlen + 1 + nlen1 > size)
449 return (ENAMETOOLONG);
450 memcpy(buf, dirf->ff_name, dlen);
452 memcpy(buf + dlen + 1, name, nlen1);
457 * Build parent name of file by splitting it off. Return an error
458 * if the given fid represents the root, so that there is no such
459 * parent, or if the discovered parent is not a directory.
462 fs_pdir(struct fs_softc *sc __unused, struct l9p_fid *fid, char *buf,
463 size_t size, struct stat *st)
471 path = r_dirname(path, buf, size);
473 return (ENAMETOOLONG);
474 if (fstatat(ff->ff_dirfd, path, st, AT_SYMLINK_NOFOLLOW) != 0)
476 if (!S_ISDIR(st->st_mode))
482 * Like fs_buildname() but for adding a file name to a buffer
483 * already holding a directory name. Essentially does
485 * strcat(dbuf, fname);
486 * but with size checking and an ENAMETOOLONG error as needed.
488 * (Think of the function name as "directory plus-equals file".)
491 fs_dpf(char *dbuf, char *fname, size_t size)
496 nlen1 = strlen(fname) + 1;
497 if (dlen + 1 + nlen1 > size)
498 return (ENAMETOOLONG);
500 memcpy(dbuf + dlen + 1, fname, nlen1);
505 * Prepare to create a new directory entry (open with O_CREAT,
506 * mkdir, etc -- any operation that creates a new inode),
507 * operating in parent data <dir>, based on authinfo <ai> and
508 * effective gid <egid>.
510 * The new entity should be owned by user/group <*nuid, *ngid>,
511 * if it's really a new entity. It will be a directory if isdir.
513 * Returns an error number if the entry should not be created
514 * (e.g., read-only file system or no permission to write in
515 * parent directory). Always sets *nuid and *ngid on success:
516 * in the worst case, when there is no available ID, this will
517 * use the parent directory's IDs. Fills in <*st> on success.
520 fs_nde(struct fs_softc *sc, struct l9p_fid *dir, bool isdir, gid_t egid,
521 struct stat *st, uid_t *nuid, gid_t *ngid)
524 struct fs_authinfo *ai;
531 assert(dirf != NULL);
532 if (fstatat(dirf->ff_dirfd, dirf->ff_name, st,
533 AT_SYMLINK_NOFOLLOW) != 0)
535 if (!S_ISDIR(st->st_mode))
540 op = isdir ? L9P_ACE_ADD_SUBDIRECTORY : L9P_ACE_ADD_FILE;
541 error = check_access(op, dirf->ff_acl, st, NULL, NULL, ai, egid);
545 *nuid = ai->ai_uid != (uid_t)-1 ? ai->ai_uid : st->st_uid;
546 *ngid = egid != (gid_t)-1 ? egid :
547 ai->ai_ngids > 0 ? ai->ai_gids[0] : st->st_gid;
552 * Allocate new open-file data structure to attach to a fid.
554 * The new file's authinfo is the same as the old one's, and
555 * we gain a reference.
557 static struct fs_fid *
558 open_fid(int dirfd, const char *path, struct fs_authinfo *ai, bool creating)
564 ret = l9p_calloc(1, sizeof(*ret));
565 error = pthread_mutex_init(&ret->ff_mtx, NULL);
571 ret->ff_dirfd = dirfd;
572 ret->ff_name = strdup(path);
573 if (ret->ff_name == NULL) {
574 pthread_mutex_destroy(&ret->ff_mtx);
578 pthread_mutex_lock(&ai->ai_mtx);
579 newcount = ++ai->ai_refcnt;
580 pthread_mutex_unlock(&ai->ai_mtx);
582 * If we just incremented the count to 1, we're the *first*
583 * reference. This is only allowed when creating the authinfo,
584 * otherwise it means something has gone wrong. This cannot
585 * catch every bad (re)use of a freed authinfo but it may catch
588 assert(newcount > 1 || creating);
589 L9P_LOG(L9P_DEBUG, "authinfo %p now used by %lu",
590 (void *)ai, (u_long)newcount);
596 dostat(struct fs_softc *sc, struct l9p_stat *s, char *name,
597 struct stat *buf, bool dotu)
602 memset(s, 0, sizeof(struct l9p_stat));
604 generate_qid(buf, &s->qid);
608 s->mode = buf->st_mode & 0777;
610 if (S_ISDIR(buf->st_mode))
611 s->mode |= L9P_DMDIR;
613 if (S_ISLNK(buf->st_mode) && dotu)
614 s->mode |= L9P_DMSYMLINK;
616 if (S_ISCHR(buf->st_mode) || S_ISBLK(buf->st_mode))
617 s->mode |= L9P_DMDEVICE;
619 if (S_ISSOCK(buf->st_mode))
620 s->mode |= L9P_DMSOCKET;
622 if (S_ISFIFO(buf->st_mode))
623 s->mode |= L9P_DMNAMEDPIPE;
625 s->atime = (uint32_t)buf->st_atime;
626 s->mtime = (uint32_t)buf->st_mtime;
627 s->length = (uint64_t)buf->st_size;
629 s->name = r_basename(name, NULL, 0);
632 struct r_pgdata udata, gdata;
634 user = fs_getpwuid(sc, buf->st_uid, &udata);
635 group = fs_getgrgid(sc, buf->st_gid, &gdata);
636 s->uid = user != NULL ? strdup(user->pw_name) : NULL;
637 s->gid = group != NULL ? strdup(group->gr_name) : NULL;
638 s->muid = user != NULL ? strdup(user->pw_name) : NULL;
643 * When using 9P2000.u, we don't need to bother about
644 * providing user and group names in textual form.
646 * NB: if the asprintf()s fail, s->extension should
647 * be unset so we can ignore these.
649 s->n_uid = buf->st_uid;
650 s->n_gid = buf->st_gid;
651 s->n_muid = buf->st_uid;
653 if (S_ISLNK(buf->st_mode)) {
654 char target[MAXPATHLEN];
655 ssize_t ret = readlink(name, target, MAXPATHLEN);
662 s->extension = strndup(target, (size_t)ret);
665 if (S_ISBLK(buf->st_mode)) {
666 asprintf(&s->extension, "b %d %d", major(buf->st_rdev),
667 minor(buf->st_rdev));
670 if (S_ISCHR(buf->st_mode)) {
671 asprintf(&s->extension, "c %d %d", major(buf->st_rdev),
672 minor(buf->st_rdev));
677 static void dostatfs(struct l9p_statfs *out, struct statfs *in, long namelen)
680 out->type = L9P_FSTYPE;
681 out->bsize = in->f_bsize;
682 out->blocks = in->f_blocks;
683 out->bfree = in->f_bfree;
684 out->bavail = in->f_bavail;
685 out->files = in->f_files;
686 out->ffree = in->f_ffree;
687 out->namelen = (uint32_t)namelen;
688 out->fsid = ((uint64_t)in->f_fsid.val[0] << 32) |
689 (uint64_t)in->f_fsid.val[1];
693 generate_qid(struct stat *buf, struct l9p_qid *qid)
695 qid->path = buf->st_ino;
698 if (S_ISREG(buf->st_mode))
699 qid->type |= L9P_QTFILE;
701 if (S_ISDIR(buf->st_mode))
702 qid->type |= L9P_QTDIR;
704 if (S_ISLNK(buf->st_mode))
705 qid->type |= L9P_QTSYMLINK;
709 * Fill in ff->ff_acl if it's not set yet. Skip if the "don't use
710 * ACLs" flag is set, and use the flag to remember failure so
711 * we don't bother retrying either.
714 fillacl(struct fs_fid *ff)
717 if (ff->ff_acl == NULL && (ff->ff_flags & FF_NO_NFSV4_ACL) == 0) {
718 ff->ff_acl = look_for_nfsv4_acl(ff, ff->ff_fd, ff->ff_name);
719 if (ff->ff_acl == NULL)
720 ff->ff_flags |= FF_NO_NFSV4_ACL;
725 * Get an ACL given fd and/or path name. We check for the "don't get
726 * ACL" flag in the given ff_fid data structure first, but don't set
727 * the flag here. The fillacl() code is similar but will set the
728 * flag; it also uses the ff_fd and ff_name directly.
730 * (This is used to get ACLs for parent directories, for instance.)
732 static struct l9p_acl *
733 getacl(struct fs_fid *ff, int fd, const char *path)
736 if (ff->ff_flags & FF_NO_NFSV4_ACL)
738 return look_for_nfsv4_acl(ff, fd, path);
742 * Drop cached ff->ff_acl, e.g., after moving from one directory to
743 * another, where inherited ACLs might change.
746 dropacl(struct fs_fid *ff)
749 l9p_acl_free(ff->ff_acl);
751 ff->ff_flags = ff->ff_ai->ai_flags;
755 * Check to see if we can find NFSv4 ACLs for the given file.
756 * If we have an open fd, we can use that, otherwise we need
759 static struct l9p_acl *
760 look_for_nfsv4_acl(struct fs_fid *ff, int fd, const char *path)
767 fd = openat(ff->ff_dirfd, path, 0);
771 sysacl = acl_get_fd_np(fd, ACL_TYPE_NFS4);
772 if (sysacl == NULL) {
774 * EINVAL means no NFSv4 ACLs apply for this file.
775 * Other error numbers indicate some kind of problem.
777 if (errno != EINVAL) {
779 "error retrieving NFSv4 ACL from "
780 "fdesc %d (%s): %s", fd,
781 path, strerror(errno));
789 #if defined(HAVE_FREEBSD_ACLS)
790 acl = l9p_freebsd_nfsv4acl_to_acl(sysacl);
792 acl = NULL; /* XXX need a l9p_darwin_acl_to_acl */
803 * Verify that the user whose authinfo is in <ai> and effective
804 * group ID is <egid> ((gid_t)-1 means no egid supplied) has
805 * permission to do something.
807 * The "something" may be rather complex: we allow NFSv4 style
808 * operation masks here, and provide parent and child ACLs and
809 * stat data. At most one of pacl+pst and cacl+cst can be NULL,
810 * unless ACLs are not supported; then pacl and cacl can both
811 * be NULL but pst or cst must be non-NULL depending on the
815 check_access(int32_t opmask,
816 struct l9p_acl *pacl, struct stat *pst,
817 struct l9p_acl *cacl, struct stat *cst,
818 struct fs_authinfo *ai, gid_t egid)
820 struct l9p_acl_check_args args;
823 * If we have ACLs, use them exclusively, ignoring Unix
824 * permissions. Otherwise, fall back on stat st_mode
825 * bits, and allow super-user as well.
827 args.aca_uid = ai->ai_uid;
829 args.aca_groups = ai->ai_gids;
830 args.aca_ngroups = (size_t)ai->ai_ngids;
831 args.aca_parent = pacl;
832 args.aca_pstat = pst;
833 args.aca_child = cacl;
834 args.aca_cstat = cst;
835 args.aca_aclmode = pacl == NULL && cacl == NULL
837 : L9P_ACM_NFS_ACL | L9P_ACM_ZFS_ACL;
839 args.aca_superuser = true;
840 return (l9p_acl_check_access(opmask, &args));
844 fs_attach(void *softc, struct l9p_request *req)
846 struct fs_authinfo *ai;
847 struct fs_softc *sc = (struct fs_softc *)softc;
851 struct r_pgdata udata;
858 assert(req->lr_fid != NULL);
861 * Single-thread pwd/group related items. We have a reentrant
862 * r_getpwuid but not a reentrant r_getpwnam, and l9p_getgrlist
863 * may use non-reentrant C library getgr* routines.
865 pthread_mutex_lock(&fs_attach_mutex);
867 n_uname = req->lr_req.tattach.n_uname;
868 if (n_uname != L9P_NONUNAME) {
869 uid = (uid_t)n_uname;
870 pwd = fs_getpwuid(sc, uid, &udata);
873 "Tattach: uid %ld: no such user", (long)uid);
876 #if defined(WITH_CASPER)
877 pwd = cap_getpwnam(sc->fs_cappwd, req->lr_req.tattach.uname);
879 pwd = getpwnam(req->lr_req.tattach.uname);
883 "Tattach: %s: no such user",
884 req->lr_req.tattach.uname);
888 * If caller didn't give a numeric UID, pick it up from pwd
889 * if possible. If that doesn't work we can't continue.
891 * Note that pwd also supplies the group set. This assumes
892 * the server has the right mapping; this needs improvement.
893 * We do at least support ai->ai_ngids==0 properly now though.
895 if (uid == (uid_t)-1 && pwd != NULL)
897 if (uid == (uid_t)-1)
901 if (fstat(sc->fs_rootfd, &st) != 0)
903 else if (!S_ISDIR(st.st_mode))
907 pthread_mutex_unlock(&fs_attach_mutex);
909 "Tattach: denying uid=%ld access to rootdir: %s",
910 (long)uid, strerror(error));
912 * Pass ENOENT and ENOTDIR through for diagnosis;
913 * others become EPERM. This should not leak too
916 return (error == ENOENT || error == ENOTDIR ? error : EPERM);
921 * This either succeeds and fills in ngroups and
922 * returns non-NULL, or fails and sets ngroups to 0
923 * and returns NULL. Either way ngroups is correct.
925 gids = l9p_getgrlist(pwd->pw_name, pwd->pw_gid, &ngroups);
932 * Done with pwd and group related items that may use
933 * non-reentrant C library routines; allow other threads in.
935 pthread_mutex_unlock(&fs_attach_mutex);
937 ai = malloc(sizeof(*ai) + (size_t)ngroups * sizeof(gid_t));
942 error = pthread_mutex_init(&ai->ai_mtx, NULL);
950 ai->ai_flags = 0; /* XXX for now */
951 ai->ai_ngids = ngroups;
952 memcpy(ai->ai_gids, gids, (size_t)ngroups * sizeof(gid_t));
955 file = open_fid(sc->fs_rootfd, ".", ai, true);
957 pthread_mutex_destroy(&ai->ai_mtx);
962 req->lr_fid->lo_aux = file;
963 generate_qid(&st, &req->lr_resp.rattach.qid);
968 fs_clunk(void *softc __unused, struct l9p_fid *fid)
973 assert(file != NULL);
976 closedir(file->ff_dir);
978 } else if (file->ff_fd != -1) {
989 * We are to create a new file under some existing path,
990 * where the new file's name is in the Tcreate request and the
991 * existing path is due to a fid-based file (req->lr_fid).
993 * One op (create regular file) sets file->fd, the rest do not.
996 fs_create(void *softc, struct l9p_request *req)
1006 name = req->lr_req.tcreate.name;
1007 dmperm = req->lr_req.tcreate.perm;
1008 perm = (mode_t)(dmperm & 0777);
1010 if (dmperm & L9P_DMDIR)
1011 error = fs_imkdir(softc, dir, name, true,
1012 perm, (gid_t)-1, &st);
1013 else if (dmperm & L9P_DMSYMLINK)
1014 error = fs_isymlink(softc, dir, name,
1015 req->lr_req.tcreate.extension, (gid_t)-1, &st);
1016 else if (dmperm & L9P_DMNAMEDPIPE)
1017 error = fs_imkfifo(softc, dir, name, true,
1018 perm, (gid_t)-1, &st);
1019 else if (dmperm & L9P_DMSOCKET)
1020 error = fs_imksocket(softc, dir, name, true,
1021 perm, (gid_t)-1, &st);
1022 else if (dmperm & L9P_DMDEVICE) {
1023 unsigned int major, minor;
1028 * ??? Should this be testing < 3? For now, allow a single
1029 * integer mode with minor==0 implied.
1032 if (sscanf(req->lr_req.tcreate.extension, "%c %u %u",
1033 &type, &major, &minor) < 2) {
1047 dev = makedev(major, minor);
1048 error = fs_imknod(softc, dir, name, true, perm, dev,
1054 p9 = req->lr_req.tcreate.mode;
1055 error = fs_oflags_dotu(p9, &flags);
1058 error = fs_icreate(softc, dir, name, flags,
1059 true, perm, (gid_t)-1, &st);
1060 req->lr_resp.rcreate.iounit = req->lr_conn->lc_max_io_size;
1064 generate_qid(&st, &req->lr_resp.rcreate.qid);
1070 * https://swtch.com/plan9port/man/man9/open.html and
1071 * http://plan9.bell-labs.com/magic/man2html/5/open
1072 * say that permissions are actually
1073 * perm & (~0666 | (dir.perm & 0666))
1075 * perm & (~0777 | (dir.perm & 0777))
1076 * for directories. That is, the parent directory may
1077 * take away permissions granted by the operation.
1079 * This seems a bit restrictive; probably
1080 * there should be a control knob for this.
1082 static inline mode_t
1083 fs_p9perm(mode_t perm, mode_t dir_perm, bool isdir)
1087 perm &= ~0777 | (dir_perm & 0777);
1089 perm &= ~0666 | (dir_perm & 0666);
1094 * Internal form of create (plain file).
1096 * Our caller takes care of splitting off all the special
1097 * types of create (mknod, etc), so this is purely for files.
1098 * We receive the fs_softc <softc>, the directory fid <dir>
1099 * in which the new file is to be created, the name of the
1100 * new file, a flag <isp9> indicating whether to do plan9 style
1101 * permissions or Linux style permissions, the permissions <perm>,
1102 * an effective group id <egid>, and a pointer to a stat structure
1103 * <st> to fill in describing the final result on success.
1105 * On successful create, the fid switches to the newly created
1106 * file, which is now open; its associated file-name changes too.
1108 * Note that the original (dir) fid is never currently open,
1109 * so there is nothing to close.
1112 fs_icreate(void *softc, struct l9p_fid *dir, char *name, int flags,
1113 bool isp9, mode_t perm, gid_t egid, struct stat *st)
1115 struct fs_fid *file;
1118 char newname[MAXPATHLEN];
1124 * Build full path name from directory + file name. We'll
1125 * check permissions on the parent directory, then race to
1126 * create the file before anything bad happens like symlinks.
1128 * (To close this race we need to use openat(), which is
1129 * left for a later version of this code.)
1131 error = fs_buildname(dir, name, newname, sizeof(newname));
1135 /* In case of success, we will need a new file->ff_name. */
1136 name = strdup(newname);
1140 /* Check create permission and compute new file ownership. */
1141 error = fs_nde(softc, dir, false, egid, st, &uid, &gid);
1147 /* Adjust new-file permissions for Plan9 protocol. */
1149 perm = fs_p9perm(perm, st->st_mode, false);
1151 /* Create is always exclusive so O_TRUNC is irrelevant. */
1152 fd = openat(file->ff_dirfd, newname, flags | O_CREAT | O_EXCL, perm);
1159 /* Fix permissions and owner. */
1160 if (fchmod(fd, perm) != 0 ||
1161 fchown(fd, uid, gid) != 0 ||
1162 fstat(fd, st) != 0) {
1165 /* unlink(newname); ? */
1170 /* It *was* a directory; now it's a file, and it's open. */
1171 free(file->ff_name);
1172 file->ff_name = name;
1178 * Internal form of open: stat file and verify permissions (from p9
1179 * argument), then open the file-or-directory, leaving the internal
1180 * fs_fid fields set up. If we cannot open the file, return a
1181 * suitable error number, and leave everything unchanged.
1183 * To mitigate the race between permissions testing and the actual
1184 * open, we can stat the file twice (once with lstat() before open,
1185 * then with fstat() after). We assume O_NOFOLLOW is set in flags,
1186 * so if some other race-winner substitutes in a symlink we won't
1187 * open it here. (However, embedded symlinks, if they occur, are
1188 * still an issue. Ideally we would like to have an O_NEVERFOLLOW
1189 * that fails on embedded symlinks, and a way to pass this to
1192 * When we use opendir() we cannot pass O_NOFOLLOW, so we must rely
1193 * on substitution-detection via fstat(). To simplify the code we
1194 * just always re-check.
1196 * (For a proper fix in the future, we can require openat(), keep
1197 * each parent directory open during walk etc, and allow only final
1198 * name components with O_NOFOLLOW.)
1200 * On successful return, st has been filled in.
1203 fs_iopen(void *softc, struct l9p_fid *fid, int flags, enum l9p_omode p9,
1204 gid_t egid __unused, struct stat *st)
1206 struct fs_softc *sc = softc;
1207 struct fs_fid *file;
1215 /* Forbid write ops on read-only file system. */
1216 if (sc->fs_readonly) {
1217 if ((flags & O_TRUNC) != 0)
1219 if ((flags & O_ACCMODE) != O_RDONLY)
1221 if (p9 & L9P_ORCLOSE)
1226 assert(file != NULL);
1227 name = file->ff_name;
1229 if (fstatat(file->ff_dirfd, name, &first, AT_SYMLINK_NOFOLLOW) != 0)
1231 if (S_ISLNK(first.st_mode))
1234 /* Can we rely on O_APPEND here? Best not, can be cleared. */
1235 switch (flags & O_ACCMODE) {
1237 op = L9P_ACE_READ_DATA;
1240 op = L9P_ACE_WRITE_DATA;
1243 op = L9P_ACE_READ_DATA | L9P_ACE_WRITE_DATA;
1249 error = check_access(op, NULL, NULL, file->ff_acl, &first,
1250 file->ff_ai, (gid_t)-1);
1254 if (S_ISDIR(first.st_mode)) {
1255 /* Forbid write or truncate on directory. */
1256 if ((flags & O_ACCMODE) != O_RDONLY || (flags & O_TRUNC))
1258 fd = openat(file->ff_dirfd, name, O_DIRECTORY);
1259 dirp = fdopendir(fd);
1265 fd = openat(file->ff_dirfd, name, flags);
1271 * We have a valid fd, and maybe non-null dirp. Re-check
1272 * the file, and fail if st_dev or st_ino changed.
1274 if (fstat(fd, st) != 0 ||
1275 first.st_dev != st->st_dev ||
1276 first.st_ino != st->st_ino) {
1278 (void) closedir(dirp);
1284 file->ff_dir = dirp;
1291 * Internal form of mkdir (common code for all forms).
1292 * We receive the fs_softc <softc>, the directory fid <dir>
1293 * in which the new entry is to be created, the name of the
1294 * new entry, a flag <isp9> indicating whether to do plan9 style
1295 * permissions or Linux style permissions, the permissions <perm>,
1296 * an effective group id <egid>, and a pointer to a stat structure
1297 * <st> to fill in describing the final result on success.
1299 * See also fs_icreate() above.
1302 fs_imkdir(void *softc, struct l9p_fid *dir, char *name,
1303 bool isp9, mode_t perm, gid_t egid, struct stat *st)
1308 char newname[MAXPATHLEN];
1312 error = fs_buildname(dir, name, newname, sizeof(newname));
1316 error = fs_nde(softc, dir, true, egid, st, &uid, &gid);
1321 perm = fs_p9perm(perm, st->st_mode, true);
1323 if (mkdirat(ff->ff_dirfd, newname, perm) != 0)
1326 fd = openat(ff->ff_dirfd, newname,
1327 O_DIRECTORY | O_RDONLY | O_NOFOLLOW);
1329 fchown(fd, uid, gid) != 0 ||
1330 fchmod(fd, perm) != 0 ||
1331 fstat(fd, st) != 0) {
1333 /* rmdir(newname) ? */
1343 * This is an undocumented OS X syscall. It would be best to avoid it,
1344 * but there doesn't seem to be another safe way to implement mknodat.
1345 * Dear Apple, please implement mknodat before you remove this syscall.
1347 static int fs_ifchdir_thread_local(int fd)
1349 #pragma clang diagnostic push
1350 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
1351 return syscall(SYS___pthread_fchdir, fd);
1352 #pragma clang diagnostic pop
1357 * Internal form of mknod (special device).
1359 * The device type (S_IFBLK, S_IFCHR) is included in the <mode> parameter.
1362 fs_imknod(void *softc, struct l9p_fid *dir, char *name,
1363 bool isp9, mode_t mode, dev_t dev, gid_t egid, struct stat *st)
1369 char newname[MAXPATHLEN];
1373 error = fs_buildname(dir, name, newname, sizeof(newname));
1377 error = fs_nde(softc, dir, false, egid, st, &uid, &gid);
1382 perm = fs_p9perm(mode & 0777, st->st_mode, false);
1383 mode = (mode & ~0777) | perm;
1389 if (fs_ifchdir_thread_local(ff->ff_dirfd) < 0) {
1392 error = mknod(newname, mode, dev);
1393 int preserved_errno = errno;
1394 /* Stop using the thread-local cwd */
1395 fs_ifchdir_thread_local(-1);
1397 errno = preserved_errno;
1401 if (mknodat(ff->ff_dirfd, newname, mode, dev) != 0)
1405 /* We cannot open the new name; race to use l* syscalls. */
1406 if (fchownat(ff->ff_dirfd, newname, uid, gid, AT_SYMLINK_NOFOLLOW) != 0 ||
1407 fchmodat(ff->ff_dirfd, newname, perm, AT_SYMLINK_NOFOLLOW) != 0 ||
1408 fstatat(ff->ff_dirfd, newname, st, AT_SYMLINK_NOFOLLOW) != 0)
1410 else if ((st->st_mode & S_IFMT) != (mode & S_IFMT))
1411 error = EPERM; /* ??? lost a race anyway */
1413 /* if (error) unlink(newname) ? */
1419 * Internal form of mkfifo.
1422 fs_imkfifo(void *softc, struct l9p_fid *dir, char *name,
1423 bool isp9, mode_t perm, gid_t egid, struct stat *st)
1428 char newname[MAXPATHLEN];
1432 error = fs_buildname(dir, name, newname, sizeof(newname));
1436 error = fs_nde(softc, dir, false, egid, st, &uid, &gid);
1441 perm = fs_p9perm(perm, st->st_mode, false);
1443 if (mkfifo(newname, perm) != 0)
1446 /* We cannot open the new name; race to use l* syscalls. */
1447 if (fchownat(ff->ff_dirfd, newname, uid, gid, AT_SYMLINK_NOFOLLOW) != 0 ||
1448 fchmodat(ff->ff_dirfd, newname, perm, AT_SYMLINK_NOFOLLOW) != 0 ||
1449 fstatat(ff->ff_dirfd, newname, st, AT_SYMLINK_NOFOLLOW) != 0)
1451 else if (!S_ISFIFO(st->st_mode))
1452 error = EPERM; /* ??? lost a race anyway */
1454 /* if (error) unlink(newname) ? */
1460 * Internal form of mksocket.
1462 * This is a bit different because of the horrible socket naming
1463 * system (bind() with sockaddr_un sun_path).
1466 fs_imksocket(void *softc, struct l9p_fid *dir, char *name,
1467 bool isp9, mode_t perm, gid_t egid, struct stat *st)
1470 struct sockaddr_un sun;
1472 char newname[MAXPATHLEN];
1475 int error = 0, s, fd;
1478 error = fs_buildname(dir, name, newname, sizeof(newname));
1482 error = fs_nde(softc, dir, false, egid, st, &uid, &gid);
1487 perm = fs_p9perm(perm, st->st_mode, false);
1489 s = socket(AF_UNIX, SOCK_STREAM, 0);
1496 /* Try bindat() if needed. */
1497 if (strlen(path) >= sizeof(sun.sun_path)) {
1498 fd = openat(ff->ff_dirfd, ff->ff_name,
1499 O_RDONLY | O_DIRECTORY | O_NOFOLLOW);
1506 * Can only create the socket if the path will fit.
1507 * Even if we are using bindat() there are limits
1508 * (the API for AF_UNIX sockets is ... not good).
1510 * Note: in theory we can fill sun_path to the end
1511 * (omitting a terminating '\0') but in at least one
1512 * Unix-like system, this was known to behave oddly,
1513 * so we test for ">=" rather than just ">".
1515 if (strlen(path) >= sizeof(sun.sun_path)) {
1516 error = ENAMETOOLONG;
1519 sun.sun_family = AF_UNIX;
1520 sun.sun_len = sizeof(struct sockaddr_un);
1521 strncpy(sun.sun_path, path, sizeof(sun.sun_path));
1525 if (bindat(fd, s, (struct sockaddr *)&sun, sun.sun_len) < 0)
1527 goto out; /* done now, for good or ill */
1531 if (bind(s, (struct sockaddr *)&sun, sun.sun_len) < 0)
1537 * We believe we created the socket-inode. Fix
1538 * permissions etc. Note that we cannot use
1539 * fstat() on the socket descriptor: it succeeds,
1540 * but we get bogus data!
1542 if (fchownat(ff->ff_dirfd, newname, uid, gid, AT_SYMLINK_NOFOLLOW) != 0 ||
1543 fchmodat(ff->ff_dirfd, newname, perm, AT_SYMLINK_NOFOLLOW) != 0 ||
1544 fstatat(ff->ff_dirfd, newname, st, AT_SYMLINK_NOFOLLOW) != 0)
1546 else if (!S_ISSOCK(st->st_mode))
1547 error = EPERM; /* ??? lost a race anyway */
1549 /* if (error) unlink(newname) ? */
1553 * It's not clear which error should override, although
1554 * ideally we should never see either close() call fail.
1555 * In any case we do want to try to close both fd and s,
1556 * always. Let's set error only if it is not already set,
1557 * so that all exit paths can use the same code.
1559 if (fd >= 0 && close(fd) != 0)
1570 * Internal form of symlink.
1572 * Note that symlinks are presumed to carry no permission bits.
1573 * They do have owners, however (who may be charged for quotas).
1576 fs_isymlink(void *softc, struct l9p_fid *dir, char *name,
1577 char *symtgt, gid_t egid, struct stat *st)
1582 char newname[MAXPATHLEN];
1586 error = fs_buildname(dir, name, newname, sizeof(newname));
1590 error = fs_nde(softc, dir, false, egid, st, &uid, &gid);
1594 if (symlinkat(symtgt, ff->ff_dirfd, newname) != 0)
1597 /* We cannot open the new name; race to use l* syscalls. */
1598 if (fchownat(ff->ff_dirfd, newname, uid, gid, AT_SYMLINK_NOFOLLOW) != 0 ||
1599 fstatat(ff->ff_dirfd, newname, st, AT_SYMLINK_NOFOLLOW) != 0)
1601 else if (!S_ISLNK(st->st_mode))
1602 error = EPERM; /* ??? lost a race anyway */
1604 /* if (error) unlink(newname) ? */
1610 fs_open(void *softc, struct l9p_request *req)
1612 struct l9p_fid *fid = req->lr_fid;
1617 p9 = req->lr_req.topen.mode;
1618 error = fs_oflags_dotu(p9, &flags);
1622 error = fs_iopen(softc, fid, flags, p9, (gid_t)-1, &st);
1626 generate_qid(&st, &req->lr_resp.ropen.qid);
1627 req->lr_resp.ropen.iounit = req->lr_conn->lc_max_io_size;
1632 * Helper for directory read. We want to run an lstat on each
1633 * file name within the directory. This is a lot faster if we
1634 * have lstatat (or fstatat with AT_SYMLINK_NOFOLLOW), but not
1635 * all systems do, so hide the ifdef-ed code in an inline function.
1638 fs_lstatat(struct fs_fid *file, char *name, struct stat *st)
1641 return (fstatat(dirfd(file->ff_dir), name, st, AT_SYMLINK_NOFOLLOW));
1645 fs_read(void *softc, struct l9p_request *req)
1647 struct l9p_stat l9stat;
1648 struct fs_softc *sc;
1649 struct fs_fid *file;
1650 bool dotu = req->lr_conn->lc_version >= L9P_2000U;
1654 file = req->lr_fid->lo_aux;
1655 assert(file != NULL);
1657 if (file->ff_dir != NULL) {
1660 struct l9p_message msg;
1663 pthread_mutex_lock(&file->ff_mtx);
1666 * Must use telldir before readdir since seekdir
1667 * takes cookie values. Unfortunately this wastes
1668 * a lot of time (and memory) building unneeded
1669 * cookies that can only be flushed by closing
1672 * NB: FreeBSD libc seekdir has SINGLEUSE defined,
1673 * so in fact, we can discard the cookies by
1674 * calling seekdir on them. This clears up wasted
1675 * memory at the cost of even more wasted time...
1677 * XXX: readdir/telldir/seekdir not thread safe
1679 l9p_init_msg(&msg, req, L9P_PACK);
1681 o = telldir(file->ff_dir);
1682 d = readdir(file->ff_dir);
1685 if (fs_lstatat(file, d->d_name, &st))
1687 dostat(sc, &l9stat, d->d_name, &st, dotu);
1688 if (l9p_pack_stat(&msg, req, &l9stat) != 0) {
1689 seekdir(file->ff_dir, o);
1692 #if defined(__FreeBSD__)
1693 seekdir(file->ff_dir, o);
1694 (void) readdir(file->ff_dir);
1698 pthread_mutex_unlock(&file->ff_mtx);
1700 size_t niov = l9p_truncate_iov(req->lr_data_iov,
1701 req->lr_data_niov, req->lr_req.io.count);
1703 #if defined(__FreeBSD__)
1704 ret = preadv(file->ff_fd, req->lr_data_iov, niov,
1705 req->lr_req.io.offset);
1707 /* XXX: not thread safe, should really use aio_listio. */
1708 if (lseek(file->ff_fd, (off_t)req->lr_req.io.offset, SEEK_SET) < 0)
1711 ret = (uint32_t)readv(file->ff_fd, req->lr_data_iov, (int)niov);
1717 req->lr_resp.io.count = (uint32_t)ret;
1724 fs_remove(void *softc, struct l9p_fid *fid)
1726 struct fs_softc *sc = softc;
1727 struct l9p_acl *parent_acl;
1728 struct fs_fid *file;
1729 struct stat pst, cst;
1730 char dirname[MAXPATHLEN];
1733 if (sc->fs_readonly)
1736 error = fs_pdir(sc, fid, dirname, sizeof(dirname), &pst);
1741 if (fstatat(file->ff_dirfd, file->ff_name, &cst, AT_SYMLINK_NOFOLLOW) != 0)
1744 parent_acl = getacl(file, -1, dirname);
1747 error = check_access(L9P_ACOP_UNLINK,
1748 parent_acl, &pst, file->ff_acl, &cst, file->ff_ai, (gid_t)-1);
1749 l9p_acl_free(parent_acl);
1753 if (unlinkat(file->ff_dirfd, file->ff_name,
1754 S_ISDIR(cst.st_mode) ? AT_REMOVEDIR : 0) != 0)
1761 fs_stat(void *softc, struct l9p_request *req)
1763 struct fs_softc *sc;
1764 struct fs_fid *file;
1766 bool dotu = req->lr_conn->lc_version >= L9P_2000U;
1769 file = req->lr_fid->lo_aux;
1772 if (fstatat(file->ff_dirfd, file->ff_name, &st,
1773 AT_SYMLINK_NOFOLLOW) != 0)
1776 dostat(sc, &req->lr_resp.rstat.stat, file->ff_name, &st, dotu);
1781 fs_walk(void *softc, struct l9p_request *req)
1783 struct l9p_acl *acl;
1784 struct fs_authinfo *ai;
1785 struct fs_fid *file = req->lr_fid->lo_aux;
1786 struct fs_fid *newfile;
1788 size_t clen, namelen, need;
1789 char *comp, *succ, *next, *swtmp;
1794 char namebufs[2][MAXPATHLEN];
1797 * https://swtch.com/plan9port/man/man9/walk.html:
1799 * It is legal for nwname to be zero, in which case newfid
1800 * will represent the same file as fid and the walk will
1801 * usually succeed; this is equivalent to walking to dot.
1802 * [Aside: it's not clear if we should test S_ISDIR here.]
1804 * The name ".." ... represents the parent directory.
1805 * The name "." ... is not used in the protocol.
1806 * ... A walk of the name ".." in the root directory
1807 * of the server is equivalent to a walk with no name
1810 * Note that req.twalk.nwname never exceeds L9P_MAX_WELEM,
1811 * so it is safe to convert to plain int.
1813 * We are to return an error only if the first walk fails,
1814 * else stop at the end of the names or on the first error.
1815 * The final fid is based on the last name successfully
1818 * Note that we *do* get Twalk requests with nwname==0 on files.
1820 * Set up "successful name" buffer pointer with base fid name,
1821 * initially. We'll swap each new success into it as we go.
1823 * Invariant: atroot and stat data correspond to current
1828 namelen = strlcpy(succ, file->ff_name, MAXPATHLEN);
1829 if (namelen >= MAXPATHLEN)
1830 return (ENAMETOOLONG);
1831 if (fstatat(file->ff_dirfd, succ, &st, AT_SYMLINK_NOFOLLOW) < 0)
1834 atroot = strlen(succ) == 0; /* XXX? */
1838 nwname = (int)req->lr_req.twalk.nwname;
1840 for (i = 0; i < nwname; i++) {
1842 * Must have execute permission to search a directory.
1843 * Then, look up each component in its directory-so-far.
1844 * Check for ".." along the way, handlng specially
1845 * as needed. Forbid "/" in name components.
1848 if (!S_ISDIR(st.st_mode)) {
1852 error = check_access(L9P_ACE_EXECUTE,
1853 NULL, NULL, acl, &st, ai, (gid_t)-1);
1856 "Twalk: denying dir-walk on \"%s\" for uid %u",
1857 succ, (unsigned)ai->ai_uid);
1861 comp = req->lr_req.twalk.wname[i];
1862 if (strchr(comp, '/') != NULL) {
1867 clen = strlen(comp);
1871 * Build next pathname (into "next"). If "..",
1872 * just strip one name component off the success
1873 * name so far. Since we know this name fits, the
1874 * stripped down version also fits. Otherwise,
1875 * the name is the base name plus '/' plus the
1876 * component name plus terminating '\0'; this may
1879 if (comp[0] == '.') {
1884 if (comp[1] == '.' && clen == 2)
1889 * It's not clear how ".." at root should
1890 * be handled when i > 0. Obeying the man
1891 * page exactly, we reset i to 0 and stop,
1892 * declaring terminal success.
1894 * Otherwise, we just climbed up one level
1895 * so adjust "atroot".
1901 (void) r_dirname(succ, next, MAXPATHLEN);
1902 namelen = strlen(next);
1903 atroot = strlen(next) == 0; /* XXX? */
1905 need = namelen + 1 + clen + 1;
1906 if (need > MAXPATHLEN) {
1907 error = ENAMETOOLONG;
1910 memcpy(next, succ, namelen);
1911 next[namelen++] = '/';
1912 memcpy(&next[namelen], comp, clen + 1);
1915 * Since name is never ".", we are necessarily
1916 * descending below the root now.
1921 if (fstatat(file->ff_dirfd, next, &st, AT_SYMLINK_NOFOLLOW) < 0) {
1927 * Success: generate qid and swap this
1928 * successful name into place. Update acl.
1930 generate_qid(&st, &req->lr_resp.rwalk.wqid[i]);
1934 if (acl != NULL && acl != file->ff_acl)
1936 acl = getacl(file, -1, next);
1940 * Fail only if we failed on the first name.
1941 * Otherwise we succeeded on something, and "succ"
1942 * points to the last successful name in namebufs[].
1950 newfile = open_fid(file->ff_dirfd, succ, ai, false);
1951 if (newfile == NULL) {
1955 if (req->lr_newfid == req->lr_fid) {
1957 * Before overwriting fid->lo_aux, free the old value.
1958 * Note that this doesn't free the l9p_fid data,
1959 * just the fs_fid data. (But it does ditch ff_acl.)
1961 if (acl == file->ff_acl)
1963 fs_freefid(softc, req->lr_fid);
1966 req->lr_newfid->lo_aux = newfile;
1967 if (file != NULL && acl != file->ff_acl) {
1968 newfile->ff_acl = acl;
1971 req->lr_resp.rwalk.nwqid = (uint16_t)i;
1973 if (file != NULL && acl != file->ff_acl)
1979 fs_write(void *softc, struct l9p_request *req)
1981 struct fs_softc *sc = softc;
1982 struct fs_fid *file;
1985 file = req->lr_fid->lo_aux;
1986 assert(file != NULL);
1988 if (sc->fs_readonly)
1991 size_t niov = l9p_truncate_iov(req->lr_data_iov,
1992 req->lr_data_niov, req->lr_req.io.count);
1994 #if defined(__FreeBSD__)
1995 ret = pwritev(file->ff_fd, req->lr_data_iov, niov,
1996 req->lr_req.io.offset);
1998 /* XXX: not thread safe, should really use aio_listio. */
1999 if (lseek(file->ff_fd, (off_t)req->lr_req.io.offset, SEEK_SET) < 0)
2002 ret = writev(file->ff_fd, req->lr_data_iov,
2009 req->lr_resp.io.count = (uint32_t)ret;
2014 fs_wstat(void *softc, struct l9p_request *req)
2016 struct fs_softc *sc = softc;
2017 struct l9p_stat *l9stat = &req->lr_req.twstat.stat;
2018 struct l9p_fid *fid;
2019 struct fs_fid *file;
2024 assert(file != NULL);
2031 * Either all the changes in wstat request happen, or none of them
2032 * does: if the request succeeds, all changes were made; if it fails,
2035 * Atomicity is clearly missing in current implementation.
2038 if (sc->fs_readonly)
2041 if (l9stat->atime != (uint32_t)~0) {
2042 /* XXX: not implemented, ignore */
2045 if (l9stat->mtime != (uint32_t)~0) {
2046 /* XXX: not implemented, ignore */
2049 if (l9stat->dev != (uint32_t)~0) {
2054 if (l9stat->length != (uint64_t)~0) {
2055 if (file->ff_dir != NULL) {
2060 if (truncate(file->ff_name, (off_t)l9stat->length) != 0) {
2066 if (req->lr_conn->lc_version >= L9P_2000U) {
2067 if (fchownat(file->ff_dirfd, file->ff_name, l9stat->n_uid,
2068 l9stat->n_gid, AT_SYMLINK_NOFOLLOW) != 0) {
2074 if (l9stat->mode != (uint32_t)~0) {
2075 if (fchmodat(file->ff_dirfd, file->ff_name,
2076 l9stat->mode & 0777, 0) != 0) {
2082 if (strlen(l9stat->name) > 0) {
2083 struct l9p_acl *parent_acl;
2086 char newname[MAXPATHLEN];
2089 * Rename-within-directory: it's not deleting anything,
2090 * but we need write permission on the directory. This
2093 error = fs_pdir(softc, fid, newname, sizeof(newname), &st);
2096 parent_acl = getacl(file, -1, newname);
2097 error = check_access(L9P_ACE_ADD_FILE,
2098 parent_acl, &st, NULL, NULL, file->ff_ai, (gid_t)-1);
2099 l9p_acl_free(parent_acl);
2102 error = fs_dpf(newname, l9stat->name, sizeof(newname));
2105 tmp = strdup(newname);
2110 if (renameat(file->ff_dirfd, file->ff_name, file->ff_dirfd,
2116 /* Successful rename, update file->ff_name. ACL can stay. */
2117 free(file->ff_name);
2118 file->ff_name = tmp;
2125 fs_statfs(void *softc __unused, struct l9p_request *req)
2127 struct fs_fid *file;
2134 file = req->lr_fid->lo_aux;
2137 if (fstatat(file->ff_dirfd, file->ff_name, &st,
2138 AT_SYMLINK_NOFOLLOW) != 0)
2142 * Not entirely clear what access to require; we'll go
2146 error = check_access(L9P_ACE_READ_DATA, NULL, NULL,
2147 file->ff_acl, &st, file->ff_ai, (gid_t)-1);
2151 fd = openat(file->ff_dirfd, file->ff_name, 0);
2155 if (fstatfs(fd, &f) != 0)
2158 name_max = fpathconf(fd, _PC_NAME_MAX);
2165 dostatfs(&req->lr_resp.rstatfs.statfs, &f, name_max);
2171 fs_lopen(void *softc, struct l9p_request *req)
2173 struct l9p_fid *fid = req->lr_fid;
2179 error = fs_oflags_dotl(req->lr_req.tlopen.flags, &flags, &p9);
2183 gid = req->lr_req.tlopen.gid;
2184 error = fs_iopen(softc, fid, flags, p9, gid, &st);
2188 generate_qid(&st, &req->lr_resp.rlopen.qid);
2189 req->lr_resp.rlopen.iounit = req->lr_conn->lc_max_io_size;
2194 fs_lcreate(void *softc, struct l9p_request *req)
2196 struct l9p_fid *dir;
2205 name = req->lr_req.tlcreate.name;
2207 error = fs_oflags_dotl(req->lr_req.tlcreate.flags, &flags, &p9);
2211 perm = (mode_t)req->lr_req.tlcreate.mode & 0777; /* ? set-id bits? */
2212 gid = req->lr_req.tlcreate.gid;
2213 error = fs_icreate(softc, dir, name, flags, false, perm, gid, &st);
2215 generate_qid(&st, &req->lr_resp.rlcreate.qid);
2216 req->lr_resp.rlcreate.iounit = req->lr_conn->lc_max_io_size;
2221 fs_symlink(void *softc, struct l9p_request *req)
2223 struct l9p_fid *dir;
2226 char *name, *symtgt;
2230 name = req->lr_req.tsymlink.name;
2231 symtgt = req->lr_req.tsymlink.symtgt;
2232 gid = req->lr_req.tsymlink.gid;
2233 error = fs_isymlink(softc, dir, name, symtgt, gid, &st);
2235 generate_qid(&st, &req->lr_resp.rsymlink.qid);
2240 fs_mknod(void *softc, struct l9p_request *req)
2242 struct l9p_fid *dir;
2244 uint32_t mode, major, minor;
2251 name = req->lr_req.tmknod.name;
2252 mode = req->lr_req.tmknod.mode;
2253 gid = req->lr_req.tmknod.gid;
2255 switch (mode & S_IFMT) {
2258 mode = (mode & S_IFMT) | (mode & 0777); /* ??? */
2259 major = req->lr_req.tmknod.major;
2260 minor = req->lr_req.tmknod.major;
2261 dev = makedev(major, minor);
2262 error = fs_imknod(softc, dir, name, false,
2263 (mode_t)mode, dev, gid, &st);
2267 error = fs_imkfifo(softc, dir, name, false,
2268 (mode_t)(mode & 0777), gid, &st);
2272 error = fs_imksocket(softc, dir, name, false,
2273 (mode_t)(mode & 0777), gid, &st);
2281 generate_qid(&st, &req->lr_resp.rmknod.qid);
2286 fs_rename(void *softc, struct l9p_request *req)
2288 struct fs_softc *sc = softc;
2289 struct fs_authinfo *ai;
2290 struct l9p_acl *oparent_acl;
2291 struct l9p_fid *fid, *f2;
2292 struct fs_fid *file, *f2ff;
2293 struct stat cst, opst, npst;
2297 char olddir[MAXPATHLEN], newname[MAXPATHLEN];
2300 if (sc->fs_readonly)
2304 * Note: lr_fid represents the file that is to be renamed,
2305 * so we must locate its parent directory and verify that
2306 * both this parent directory and the new directory f2 are
2307 * writable. But if the new parent directory is the same
2308 * path as the old parent directory, our job is simpler.
2312 assert(file != NULL);
2315 error = fs_pdir(sc, fid, olddir, sizeof(olddir), &opst);
2321 assert(f2ff != NULL);
2323 reparenting = strcmp(olddir, f2ff->ff_name) != 0;
2328 if (fstatat(file->ff_dirfd, file->ff_name, &cst,
2329 AT_SYMLINK_NOFOLLOW) != 0)
2333 * Are we moving from olddir? If so, we're unlinking
2334 * from it, in terms of ACL access.
2337 oparent_acl = getacl(file, -1, olddir);
2338 error = check_access(L9P_ACOP_UNLINK,
2339 oparent_acl, &opst, file->ff_acl, &cst, ai, (gid_t)-1);
2340 l9p_acl_free(oparent_acl);
2346 * Now check that we're allowed to "create" a file or directory in
2347 * f2. (Should we do this, too, only if reparenting? Maybe check
2348 * for dir write permission if not reparenting -- but that's just
2349 * add-file/add-subdir, which means doing this always.)
2351 if (fstatat(f2ff->ff_dirfd, f2ff->ff_name, &npst,
2352 AT_SYMLINK_NOFOLLOW) != 0)
2355 op = S_ISDIR(cst.st_mode) ? L9P_ACE_ADD_SUBDIRECTORY : L9P_ACE_ADD_FILE;
2356 error = check_access(op, f2ff->ff_acl, &npst, NULL, NULL,
2362 * Directories OK, file systems not R/O, etc; build final name.
2363 * f2ff->ff_name cannot exceed MAXPATHLEN, but out of general
2364 * paranoia, let's double check anyway.
2366 if (strlcpy(newname, f2ff->ff_name, sizeof(newname)) >= sizeof(newname))
2367 return (ENAMETOOLONG);
2368 error = fs_dpf(newname, req->lr_req.trename.name, sizeof(newname));
2371 tmp = strdup(newname);
2375 if (renameat(file->ff_dirfd, file->ff_name, file->ff_dirfd, tmp) != 0) {
2381 /* file has been renamed but old fid is not clunked */
2382 free(file->ff_name);
2383 file->ff_name = tmp;
2390 fs_readlink(void *softc __unused, struct l9p_request *req)
2392 struct fs_fid *file;
2394 char buf[MAXPATHLEN];
2397 file = req->lr_fid->lo_aux;
2400 linklen = readlinkat(file->ff_dirfd, file->ff_name, buf, sizeof(buf));
2403 else if ((size_t)linklen >= sizeof(buf))
2404 error = ENOMEM; /* todo: allocate dynamically */
2405 else if ((req->lr_resp.rreadlink.target = strndup(buf,
2406 (size_t)linklen)) == NULL)
2412 fs_getattr(void *softc __unused, struct l9p_request *req)
2414 uint64_t mask, valid;
2415 struct fs_fid *file;
2419 file = req->lr_fid->lo_aux;
2423 if (fstatat(file->ff_dirfd, file->ff_name, &st, AT_SYMLINK_NOFOLLOW)) {
2427 /* ?? Can we provide items not-requested? If so, can skip tests. */
2428 mask = req->lr_req.tgetattr.request_mask;
2429 if (mask & L9PL_GETATTR_MODE) {
2430 /* It is not clear if we need any translations. */
2431 req->lr_resp.rgetattr.mode = st.st_mode;
2432 valid |= L9PL_GETATTR_MODE;
2434 if (mask & L9PL_GETATTR_NLINK) {
2435 req->lr_resp.rgetattr.nlink = st.st_nlink;
2436 valid |= L9PL_GETATTR_NLINK;
2438 if (mask & L9PL_GETATTR_UID) {
2439 /* provide st_uid, or file->ff_uid? */
2440 req->lr_resp.rgetattr.uid = st.st_uid;
2441 valid |= L9PL_GETATTR_UID;
2443 if (mask & L9PL_GETATTR_GID) {
2444 /* provide st_gid, or file->ff_gid? */
2445 req->lr_resp.rgetattr.gid = st.st_gid;
2446 valid |= L9PL_GETATTR_GID;
2448 if (mask & L9PL_GETATTR_RDEV) {
2449 /* It is not clear if we need any translations. */
2450 req->lr_resp.rgetattr.rdev = (uint64_t)st.st_rdev;
2451 valid |= L9PL_GETATTR_RDEV;
2453 if (mask & L9PL_GETATTR_ATIME) {
2454 req->lr_resp.rgetattr.atime_sec =
2455 (uint64_t)st.st_atimespec.tv_sec;
2456 req->lr_resp.rgetattr.atime_nsec =
2457 (uint64_t)st.st_atimespec.tv_nsec;
2458 valid |= L9PL_GETATTR_ATIME;
2460 if (mask & L9PL_GETATTR_MTIME) {
2461 req->lr_resp.rgetattr.mtime_sec =
2462 (uint64_t)st.st_mtimespec.tv_sec;
2463 req->lr_resp.rgetattr.mtime_nsec =
2464 (uint64_t)st.st_mtimespec.tv_nsec;
2465 valid |= L9PL_GETATTR_MTIME;
2467 if (mask & L9PL_GETATTR_CTIME) {
2468 req->lr_resp.rgetattr.ctime_sec =
2469 (uint64_t)st.st_ctimespec.tv_sec;
2470 req->lr_resp.rgetattr.ctime_nsec =
2471 (uint64_t)st.st_ctimespec.tv_nsec;
2472 valid |= L9PL_GETATTR_CTIME;
2474 if (mask & L9PL_GETATTR_BTIME) {
2475 #if defined(HAVE_BIRTHTIME)
2476 req->lr_resp.rgetattr.btime_sec =
2477 (uint64_t)st.st_birthtim.tv_sec;
2478 req->lr_resp.rgetattr.btime_nsec =
2479 (uint64_t)st.st_birthtim.tv_nsec;
2481 req->lr_resp.rgetattr.btime_sec = 0;
2482 req->lr_resp.rgetattr.btime_nsec = 0;
2484 valid |= L9PL_GETATTR_BTIME;
2486 if (mask & L9PL_GETATTR_INO)
2487 valid |= L9PL_GETATTR_INO;
2488 if (mask & L9PL_GETATTR_SIZE) {
2489 req->lr_resp.rgetattr.size = (uint64_t)st.st_size;
2490 valid |= L9PL_GETATTR_SIZE;
2492 if (mask & L9PL_GETATTR_BLOCKS) {
2493 req->lr_resp.rgetattr.blksize = (uint64_t)st.st_blksize;
2494 req->lr_resp.rgetattr.blocks = (uint64_t)st.st_blocks;
2495 valid |= L9PL_GETATTR_BLOCKS;
2497 if (mask & L9PL_GETATTR_GEN) {
2498 req->lr_resp.rgetattr.gen = st.st_gen;
2499 valid |= L9PL_GETATTR_GEN;
2501 /* don't know what to do with data version yet */
2503 generate_qid(&st, &req->lr_resp.rgetattr.qid);
2505 req->lr_resp.rgetattr.valid = valid;
2510 * Should combine some of this with wstat code.
2513 fs_setattr(void *softc, struct l9p_request *req)
2516 struct fs_softc *sc = softc;
2517 struct timespec ts[2];
2518 struct fs_fid *file;
2523 file = req->lr_fid->lo_aux;
2526 if (sc->fs_readonly)
2530 * As with WSTAT we have atomicity issues.
2532 mask = req->lr_req.tsetattr.valid;
2534 if (fstatat(file->ff_dirfd, file->ff_name, &st, AT_SYMLINK_NOFOLLOW)) {
2539 if ((mask & L9PL_SETATTR_SIZE) && S_ISDIR(st.st_mode)) {
2544 if (mask & L9PL_SETATTR_MODE) {
2545 if (fchmodat(file->ff_dirfd, file->ff_name,
2546 req->lr_req.tsetattr.mode & 0777,
2547 AT_SYMLINK_NOFOLLOW)) {
2553 if (mask & (L9PL_SETATTR_UID | L9PL_SETATTR_GID)) {
2554 uid = mask & L9PL_SETATTR_UID
2555 ? req->lr_req.tsetattr.uid
2558 gid = mask & L9PL_SETATTR_GID
2559 ? req->lr_req.tsetattr.gid
2562 if (fchownat(file->ff_dirfd, file->ff_name, uid, gid,
2563 AT_SYMLINK_NOFOLLOW)) {
2569 if (mask & L9PL_SETATTR_SIZE) {
2570 /* Truncate follows symlinks, is this OK? */
2571 int fd = openat(file->ff_dirfd, file->ff_name, O_RDWR);
2572 if (ftruncate(fd, (off_t)req->lr_req.tsetattr.size)) {
2580 if (mask & (L9PL_SETATTR_ATIME | L9PL_SETATTR_MTIME)) {
2581 ts[0].tv_sec = st.st_atimespec.tv_sec;
2582 ts[0].tv_nsec = st.st_atimespec.tv_nsec;
2583 ts[1].tv_sec = st.st_mtimespec.tv_sec;
2584 ts[1].tv_nsec = st.st_mtimespec.tv_nsec;
2586 if (mask & L9PL_SETATTR_ATIME) {
2587 if (mask & L9PL_SETATTR_ATIME_SET) {
2588 ts[0].tv_sec = req->lr_req.tsetattr.atime_sec;
2589 ts[0].tv_nsec = req->lr_req.tsetattr.atime_nsec;
2591 if (clock_gettime(CLOCK_REALTIME, &ts[0]) != 0) {
2598 if (mask & L9PL_SETATTR_MTIME) {
2599 if (mask & L9PL_SETATTR_MTIME_SET) {
2600 ts[1].tv_sec = req->lr_req.tsetattr.mtime_sec;
2601 ts[1].tv_nsec = req->lr_req.tsetattr.mtime_nsec;
2603 if (clock_gettime(CLOCK_REALTIME, &ts[1]) != 0) {
2610 if (utimensat(file->ff_dirfd, file->ff_name, ts,
2611 AT_SYMLINK_NOFOLLOW)) {
2621 fs_xattrwalk(void *softc __unused, struct l9p_request *req __unused)
2623 return (EOPNOTSUPP);
2627 fs_xattrcreate(void *softc __unused, struct l9p_request *req __unused)
2629 return (EOPNOTSUPP);
2633 fs_readdir(void *softc __unused, struct l9p_request *req)
2635 struct l9p_message msg;
2636 struct l9p_dirent de;
2637 struct fs_fid *file;
2643 file = req->lr_fid->lo_aux;
2646 if (file->ff_dir == NULL)
2649 pthread_mutex_lock(&file->ff_mtx);
2652 * It's not clear whether we can use the same trick for
2653 * discarding offsets here as we do in fs_read. It
2654 * probably should work, we'll have to see if some
2655 * client(s) use the zero-offset thing to rescan without
2656 * clunking the directory first.
2658 * Probably the thing to do is switch to calling
2659 * getdirentries() / getdents() directly, instead of
2660 * going through libc.
2662 if (req->lr_req.io.offset == 0)
2663 rewinddir(file->ff_dir);
2665 seekdir(file->ff_dir, (long)req->lr_req.io.offset);
2667 l9p_init_msg(&msg, req, L9P_PACK);
2668 count = (uint32_t)msg.lm_size; /* in case we get no entries */
2669 while ((dp = readdir(file->ff_dir)) != NULL) {
2671 * Although "." is forbidden in naming and ".." is
2672 * special cased, testing shows that we must transmit
2673 * them through readdir. (For ".." at root, we
2674 * should perhaps alter the inode number, but not
2679 * TODO: we do a full lstat here; could use dp->d_*
2680 * to construct the qid more efficiently, as long
2681 * as dp->d_type != DT_UNKNOWN.
2683 if (fs_lstatat(file, dp->d_name, &st))
2687 generate_qid(&st, &de.qid);
2688 de.offset = (uint64_t)telldir(file->ff_dir);
2689 de.type = dp->d_type;
2690 de.name = dp->d_name;
2692 /* Update count only if we completely pack the dirent. */
2693 if (l9p_pudirent(&msg, &de) < 0)
2695 count = (uint32_t)msg.lm_size;
2698 pthread_mutex_unlock(&file->ff_mtx);
2699 req->lr_resp.io.count = count;
2704 fs_fsync(void *softc __unused, struct l9p_request *req)
2706 struct fs_fid *file;
2709 file = req->lr_fid->lo_aux;
2711 if (fsync(file->ff_dir != NULL ? dirfd(file->ff_dir) : file->ff_fd))
2717 fs_lock(void *softc __unused, struct l9p_request *req)
2720 switch (req->lr_req.tlock.type) {
2721 case L9PL_LOCK_TYPE_RDLOCK:
2722 case L9PL_LOCK_TYPE_WRLOCK:
2723 case L9PL_LOCK_TYPE_UNLOCK:
2729 req->lr_resp.rlock.status = L9PL_LOCK_SUCCESS;
2734 fs_getlock(void *softc __unused, struct l9p_request *req)
2738 * Client wants to see if a request to lock a region would
2739 * block. This is, of course, not atomic anyway, so the
2740 * op is useless. QEMU simply says "unlocked!", so we do
2743 switch (req->lr_req.getlock.type) {
2744 case L9PL_LOCK_TYPE_RDLOCK:
2745 case L9PL_LOCK_TYPE_WRLOCK:
2746 case L9PL_LOCK_TYPE_UNLOCK:
2752 req->lr_resp.getlock = req->lr_req.getlock;
2753 req->lr_resp.getlock.type = L9PL_LOCK_TYPE_UNLOCK;
2754 req->lr_resp.getlock.client_id = strdup(""); /* XXX what should go here? */
2759 fs_link(void *softc __unused, struct l9p_request *req)
2761 struct l9p_fid *dir;
2762 struct fs_fid *file;
2763 struct fs_fid *dirf;
2764 struct stat fst, tdst;
2767 char newname[MAXPATHLEN];
2770 /* N.B.: lr_fid is the file to link, lr_fid2 is the target dir */
2773 assert(dirf != NULL);
2775 name = req->lr_req.tlink.name;
2776 error = fs_buildname(dir, name, newname, sizeof(newname));
2780 file = req->lr_fid->lo_aux;
2781 assert(file != NULL);
2783 if (fstatat(dirf->ff_dirfd, dirf->ff_name, &tdst, AT_SYMLINK_NOFOLLOW) != 0 ||
2784 fstatat(file->ff_dirfd, file->ff_name, &fst, AT_SYMLINK_NOFOLLOW) != 0)
2786 if (S_ISDIR(fst.st_mode))
2789 op = S_ISDIR(fst.st_mode) ? L9P_ACE_ADD_SUBDIRECTORY : L9P_ACE_ADD_FILE;
2790 error = check_access(op,
2791 dirf->ff_acl, &tdst, NULL, NULL, file->ff_ai, (gid_t)-1);
2795 if (linkat(file->ff_dirfd, file->ff_name, file->ff_dirfd,
2805 fs_mkdir(void *softc, struct l9p_request *req)
2807 struct l9p_fid *dir;
2815 name = req->lr_req.tmkdir.name;
2816 perm = (mode_t)req->lr_req.tmkdir.mode;
2817 gid = req->lr_req.tmkdir.gid;
2819 error = fs_imkdir(softc, dir, name, false, perm, gid, &st);
2821 generate_qid(&st, &req->lr_resp.rmkdir.qid);
2826 fs_renameat(void *softc, struct l9p_request *req)
2828 struct fs_softc *sc = softc;
2829 struct l9p_fid *olddir, *newdir;
2830 struct l9p_acl *facl;
2831 struct fs_fid *off, *nff;
2832 struct stat odst, ndst, fst;
2836 char onb[MAXPATHLEN], nnb[MAXPATHLEN];
2839 if (sc->fs_readonly)
2842 olddir = req->lr_fid;
2843 newdir = req->lr_fid2;
2844 assert(olddir != NULL && newdir != NULL);
2845 off = olddir->lo_aux;
2846 nff = newdir->lo_aux;
2847 assert(off != NULL && nff != NULL);
2849 onp = req->lr_req.trenameat.oldname;
2850 nnp = req->lr_req.trenameat.newname;
2851 error = fs_buildname(olddir, onp, onb, sizeof(onb));
2854 error = fs_buildname(newdir, nnp, nnb, sizeof(nnb));
2857 if (fstatat(off->ff_dirfd, onb, &fst, AT_SYMLINK_NOFOLLOW) != 0)
2860 reparenting = olddir != newdir &&
2861 strcmp(off->ff_name, nff->ff_name) != 0;
2863 if (fstatat(off->ff_dirfd, off->ff_name, &odst, AT_SYMLINK_NOFOLLOW) != 0)
2865 if (!S_ISDIR(odst.st_mode))
2870 if (fstatat(nff->ff_dirfd, nff->ff_name, &ndst, AT_SYMLINK_NOFOLLOW) != 0)
2872 if (!S_ISDIR(ndst.st_mode))
2874 facl = getacl(off, -1, onb);
2877 error = check_access(L9P_ACOP_UNLINK,
2878 off->ff_acl, &odst, facl, &fst, off->ff_ai, (gid_t)-1);
2882 op = S_ISDIR(fst.st_mode) ? L9P_ACE_ADD_SUBDIRECTORY :
2884 error = check_access(op,
2885 nff->ff_acl, &ndst, NULL, NULL, nff->ff_ai, (gid_t)-1);
2890 if (renameat(off->ff_dirfd, onb, nff->ff_dirfd, nnb))
2897 * Unlink file in given directory, or remove directory in given
2898 * directory, based on flags.
2901 fs_unlinkat(void *softc, struct l9p_request *req)
2903 struct fs_softc *sc = softc;
2904 struct l9p_acl *facl;
2905 struct l9p_fid *dir;
2906 struct fs_fid *dirff;
2907 struct stat dirst, fst;
2909 char newname[MAXPATHLEN];
2912 if (sc->fs_readonly)
2916 dirff = dir->lo_aux;
2917 assert(dirff != NULL);
2918 name = req->lr_req.tunlinkat.name;
2919 error = fs_buildname(dir, name, newname, sizeof(newname));
2922 if (fstatat(dirff->ff_dirfd, newname, &fst, AT_SYMLINK_NOFOLLOW) != 0 ||
2923 fstatat(dirff->ff_dirfd, dirff->ff_name, &dirst, AT_SYMLINK_NOFOLLOW) != 0)
2926 facl = getacl(dirff, -1, newname);
2927 error = check_access(L9P_ACOP_UNLINK,
2928 dirff->ff_acl, &dirst, facl, &fst, dirff->ff_ai, (gid_t)-1);
2933 if (req->lr_req.tunlinkat.flags & L9PL_AT_REMOVEDIR) {
2934 if (unlinkat(dirff->ff_dirfd, newname, AT_REMOVEDIR) != 0)
2937 if (unlinkat(dirff->ff_dirfd, newname, 0) != 0)
2944 fs_freefid(void *softc __unused, struct l9p_fid *fid)
2946 struct fs_fid *f = fid->lo_aux;
2947 struct fs_authinfo *ai;
2951 /* Nothing to do here */
2959 closedir(f->ff_dir);
2961 pthread_mutex_destroy(&f->ff_mtx);
2964 l9p_acl_free(f->ff_acl);
2966 pthread_mutex_lock(&ai->ai_mtx);
2967 newcount = --ai->ai_refcnt;
2968 pthread_mutex_unlock(&ai->ai_mtx);
2969 if (newcount == 0) {
2971 * We *were* the last ref, no one can have gained a ref.
2973 L9P_LOG(L9P_DEBUG, "dropped last ref to authinfo %p",
2975 pthread_mutex_destroy(&ai->ai_mtx);
2978 L9P_LOG(L9P_DEBUG, "authinfo %p now used by %lu",
2979 (void *)ai, (u_long)newcount);
2984 l9p_backend_fs_init(struct l9p_backend **backendp, int rootfd, bool ro)
2986 struct l9p_backend *backend;
2987 struct fs_softc *sc;
2989 #if defined(WITH_CASPER)
2990 cap_channel_t *capcas;
2993 if (!fs_attach_mutex_inited) {
2994 error = pthread_mutex_init(&fs_attach_mutex, NULL);
2999 fs_attach_mutex_inited = true;
3002 backend = l9p_malloc(sizeof(*backend));
3003 backend->attach = fs_attach;
3004 backend->clunk = fs_clunk;
3005 backend->create = fs_create;
3006 backend->open = fs_open;
3007 backend->read = fs_read;
3008 backend->remove = fs_remove;
3009 backend->stat = fs_stat;
3010 backend->walk = fs_walk;
3011 backend->write = fs_write;
3012 backend->wstat = fs_wstat;
3013 backend->statfs = fs_statfs;
3014 backend->lopen = fs_lopen;
3015 backend->lcreate = fs_lcreate;
3016 backend->symlink = fs_symlink;
3017 backend->mknod = fs_mknod;
3018 backend->rename = fs_rename;
3019 backend->readlink = fs_readlink;
3020 backend->getattr = fs_getattr;
3021 backend->setattr = fs_setattr;
3022 backend->xattrwalk = fs_xattrwalk;
3023 backend->xattrcreate = fs_xattrcreate;
3024 backend->readdir = fs_readdir;
3025 backend->fsync = fs_fsync;
3026 backend->lock = fs_lock;
3027 backend->getlock = fs_getlock;
3028 backend->link = fs_link;
3029 backend->mkdir = fs_mkdir;
3030 backend->renameat = fs_renameat;
3031 backend->unlinkat = fs_unlinkat;
3032 backend->freefid = fs_freefid;
3034 sc = l9p_malloc(sizeof(*sc));
3035 sc->fs_rootfd = rootfd;
3036 sc->fs_readonly = ro;
3037 backend->softc = sc;
3039 #if defined(WITH_CASPER)
3040 capcas = cap_init();
3044 sc->fs_cappwd = cap_service_open(capcas, "system.pwd");
3045 if (sc->fs_cappwd == NULL)
3048 sc->fs_capgrp = cap_service_open(capcas, "system.grp");
3049 if (sc->fs_capgrp == NULL)
3052 cap_setpassent(sc->fs_cappwd, 1);
3053 cap_setgroupent(sc->fs_capgrp, 1);
3059 *backendp = backend;