svn commit: r360470 - in vendor/lib9p: . dist dist/backend dist/example dist/pytest dist/sbuf dist/transport
Jakub Wojciech Klama
jceel at FreeBSD.org
Wed Apr 29 16:24:34 UTC 2020
Author: jceel
Date: Wed Apr 29 16:24:32 2020
New Revision: 360470
URL: https://svnweb.freebsd.org/changeset/base/360470
Log:
Import lib9p 7ddb1164407da19b9b1afb83df83ae65a71a9a66.
Approved by: trasz (mentor)
MFC after: 1 month
Sponsored by: Conclusive Engineering
Added:
vendor/lib9p/
vendor/lib9p/dist/
vendor/lib9p/dist/.gitignore
vendor/lib9p/dist/COPYRIGHT
vendor/lib9p/dist/GNUmakefile
vendor/lib9p/dist/Makefile (contents, props changed)
vendor/lib9p/dist/README.md
vendor/lib9p/dist/apple_endian.h (contents, props changed)
vendor/lib9p/dist/backend/
vendor/lib9p/dist/backend/backend.h (contents, props changed)
vendor/lib9p/dist/backend/fs.c (contents, props changed)
vendor/lib9p/dist/backend/fs.h (contents, props changed)
vendor/lib9p/dist/connection.c (contents, props changed)
vendor/lib9p/dist/example/
vendor/lib9p/dist/example/Makefile (contents, props changed)
vendor/lib9p/dist/example/server.c (contents, props changed)
vendor/lib9p/dist/fcall.h (contents, props changed)
vendor/lib9p/dist/fid.h (contents, props changed)
vendor/lib9p/dist/genacl.c (contents, props changed)
vendor/lib9p/dist/genacl.h (contents, props changed)
vendor/lib9p/dist/hashtable.c (contents, props changed)
vendor/lib9p/dist/hashtable.h (contents, props changed)
vendor/lib9p/dist/lib9p.h (contents, props changed)
vendor/lib9p/dist/lib9p_impl.h (contents, props changed)
vendor/lib9p/dist/linux_errno.h (contents, props changed)
vendor/lib9p/dist/log.c (contents, props changed)
vendor/lib9p/dist/log.h (contents, props changed)
vendor/lib9p/dist/pack.c (contents, props changed)
vendor/lib9p/dist/pytest/
vendor/lib9p/dist/pytest/.gitignore
vendor/lib9p/dist/pytest/Makefile (contents, props changed)
vendor/lib9p/dist/pytest/README
vendor/lib9p/dist/pytest/client.py (contents, props changed)
vendor/lib9p/dist/pytest/lerrno.py (contents, props changed)
vendor/lib9p/dist/pytest/numalloc.py (contents, props changed)
vendor/lib9p/dist/pytest/p9conn.py (contents, props changed)
vendor/lib9p/dist/pytest/p9err.py (contents, props changed)
vendor/lib9p/dist/pytest/pfod.py (contents, props changed)
vendor/lib9p/dist/pytest/protocol.py (contents, props changed)
vendor/lib9p/dist/pytest/sequencer.py (contents, props changed)
vendor/lib9p/dist/pytest/testconf.ini.sample
vendor/lib9p/dist/request.c (contents, props changed)
vendor/lib9p/dist/rfuncs.c (contents, props changed)
vendor/lib9p/dist/rfuncs.h (contents, props changed)
vendor/lib9p/dist/sbuf/
vendor/lib9p/dist/sbuf/sbuf.c (contents, props changed)
vendor/lib9p/dist/sbuf/sbuf.h (contents, props changed)
vendor/lib9p/dist/threadpool.c (contents, props changed)
vendor/lib9p/dist/threadpool.h (contents, props changed)
vendor/lib9p/dist/transport/
vendor/lib9p/dist/transport/socket.c (contents, props changed)
vendor/lib9p/dist/transport/socket.h (contents, props changed)
vendor/lib9p/dist/utils.c (contents, props changed)
Added: vendor/lib9p/dist/.gitignore
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ vendor/lib9p/dist/.gitignore Wed Apr 29 16:24:32 2020 (r360470)
@@ -0,0 +1,37 @@
+# Object files
+*.o
+*.ko
+*.obj
+*.elf
+
+# Precompiled Headers
+*.gch
+*.pch
+
+# Libraries
+*.lib
+*.a
+*.la
+*.lo
+
+# Shared objects (inc. Windows DLLs)
+*.dll
+*.so
+*.so.*
+*.dylib
+
+# Executables
+*.exe
+*.out
+*.app
+*.i*86
+*.x86_64
+*.hex
+
+# Debug files
+*.dSYM/
+/build/
+
+*.po
+*.pico
+*.depend
Added: vendor/lib9p/dist/COPYRIGHT
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ vendor/lib9p/dist/COPYRIGHT Wed Apr 29 16:24:32 2020 (r360470)
@@ -0,0 +1,47 @@
+Copyright 2016 Jakub Klama <jceel at FreeBSD.org>
+All rights reserved
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted providing that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+Some parts of the code are based on libixp (http://libs.suckless.org/libixp)
+library code released under following license:
+
+© 2005-2006 Anselm R. Garbe <garbeam at gmail.com>
+© 2006-2010 Kris Maglione <maglione.k at Gmail>
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
Added: vendor/lib9p/dist/GNUmakefile
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ vendor/lib9p/dist/GNUmakefile Wed Apr 29 16:24:32 2020 (r360470)
@@ -0,0 +1,76 @@
+CC_VERSION := $(shell $(CC) --version | \
+ sed -n -e '/clang-/s/.*clang-\([0-9][0-9]*\).*/\1/p')
+ifeq ($(CC_VERSION),)
+# probably not clang
+CC_VERSION := 0
+endif
+
+WFLAGS :=
+
+# Warnings are version-dependent, unfortunately,
+# so test for version before adding a -W flag.
+# Note: gnu make requires $(shell test ...) for "a > b" type tests.
+ifeq ($(shell test $(CC_VERSION) -gt 0; echo $$?),0)
+WFLAGS += -Weverything
+WFLAGS += -Wno-padded
+WFLAGS += -Wno-gnu-zero-variadic-macro-arguments
+WFLAGS += -Wno-format-nonliteral
+WFLAGS += -Wno-unused-macros
+WFLAGS += -Wno-disabled-macro-expansion
+WFLAGS += -Werror
+endif
+
+ifeq ($(shell test $(CC_VERSION) -gt 600; echo $$?),0)
+WFLAGS += -Wno-reserved-id-macro
+endif
+
+CFLAGS := $(WFLAGS) \
+ -g \
+ -O0 \
+ -DL9P_DEBUG=L9P_DEBUG
+# Note: to turn on debug, use -DL9P_DEBUG=L9P_DEBUG,
+# and set env variable LIB9P_LOGGING to stderr or to
+# the (preferably full path name of) the debug log file.
+
+LIB_SRCS := \
+ pack.c \
+ connection.c \
+ request.c \
+ genacl.c \
+ log.c \
+ hashtable.c \
+ utils.c \
+ rfuncs.c \
+ threadpool.c \
+ sbuf/sbuf.c \
+ transport/socket.c \
+ backend/fs.c
+
+SERVER_SRCS := \
+ example/server.c
+
+BUILD_DIR := build
+LIB_OBJS := $(addprefix build/,$(LIB_SRCS:.c=.o))
+SERVER_OBJS := $(SERVER_SRCS:.c=.o)
+LIB := lib9p.dylib
+SERVER := server
+
+all: build $(LIB) $(SERVER)
+
+$(LIB): $(LIB_OBJS)
+ cc -dynamiclib $^ -o build/$@
+
+$(SERVER): $(SERVER_OBJS) $(LIB)
+ cc $< -o build/$(SERVER) -Lbuild/ -l9p
+
+clean:
+ rm -rf build
+ rm -f $(SERVER_OBJS)
+build:
+ mkdir build
+ mkdir build/sbuf
+ mkdir build/transport
+ mkdir build/backend
+
+build/%.o: %.c
+ $(CC) $(CFLAGS) -c $< -o $@
Added: vendor/lib9p/dist/Makefile
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ vendor/lib9p/dist/Makefile Wed Apr 29 16:24:32 2020 (r360470)
@@ -0,0 +1,27 @@
+# Note: to turn on debug, use -DL9P_DEBUG=L9P_DEBUG,
+# and set env variable LIB9P_LOGGING to stderr or to
+# the (preferably full path name of) the debug log file.
+
+LIB= 9p
+SHLIB_MAJOR= 1
+SRCS= pack.c \
+ connection.c \
+ request.c log.c \
+ hashtable.c \
+ genacl.c \
+ utils.c \
+ rfuncs.c \
+ threadpool.c \
+ transport/socket.c \
+ backend/fs.c
+
+INCS= lib9p.h
+CC= clang
+CFLAGS= -g -O0 -DL9P_DEBUG=L9P_DEBUG -DWITH_CASPER
+LIBADD= sbuf libcasper libcap_pwd libcap_grp
+SUBDIR= example
+
+cscope: .PHONY
+ cd ${.CURDIR}; cscope -buq $$(find . -name '*.[ch]' -print)
+
+.include <bsd.lib.mk>
Added: vendor/lib9p/dist/README.md
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ vendor/lib9p/dist/README.md Wed Apr 29 16:24:32 2020 (r360470)
@@ -0,0 +1,20 @@
+# lib9p
+
+lib9p is a server library implementing 9p2000, 9p2000.u and 9p2000.L revisions
+of 9P protocol. It is being developed primarily as a backend for virtio-9p in
+BHyVe, the FreeBSD hypervisor.
+
+# Features
+
+* 9p2000, 9p2000.u and 9p2000.L protocol support
+* Built-in TCP transport
+
+# Supported operating systems
+
+* FreeBSD (>=10)
+* macOS (>=10.9)
+
+# Authors
+
+* Jakub Klama [jceel](https://github.com/jceel)
+* Chris Torek [chris3torek](https://github.com/chris3torek)
Added: vendor/lib9p/dist/apple_endian.h
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ vendor/lib9p/dist/apple_endian.h Wed Apr 29 16:24:32 2020 (r360470)
@@ -0,0 +1,27 @@
+#ifndef _APPLE_ENDIAN_H
+#define _APPLE_ENDIAN_H
+
+/*
+ * Shims to make Apple's endian headers and macros compatible
+ * with <sys/endian.h> (which is awful).
+ */
+
+# include <libkern/OSByteOrder.h>
+
+# define _LITTLE_ENDIAN 0x12345678
+# define _BIG_ENDIAN 0x87654321
+
+# ifdef __LITTLE_ENDIAN__
+# define _BYTE_ORDER _LITTLE_ENDIAN
+# endif
+# ifdef __BIG_ENDIAN__
+# define _BYTE_ORDER _BIG_ENDIAN
+# endif
+
+# define htole32(x) OSSwapHostToLittleInt32(x)
+# define le32toh(x) OSSwapLittleToHostInt32(x)
+
+# define htobe32(x) OSSwapHostToBigInt32(x)
+# define be32toh(x) OSSwapBigToHostInt32(x)
+
+#endif /* _APPLE_ENDIAN_H */
Added: vendor/lib9p/dist/backend/backend.h
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ vendor/lib9p/dist/backend/backend.h Wed Apr 29 16:24:32 2020 (r360470)
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2016 Jakub Klama <jceel at FreeBSD.org>
+ * All rights reserved
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted providing that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#ifndef LIB9P_BACKEND_H
+#define LIB9P_BACKEND_H
+
+struct l9p_backend {
+ void *softc;
+ void (*freefid)(void *, struct l9p_fid *);
+ int (*attach)(void *, struct l9p_request *);
+ int (*clunk)(void *, struct l9p_fid *);
+ int (*create)(void *, struct l9p_request *);
+ int (*open)(void *, struct l9p_request *);
+ int (*read)(void *, struct l9p_request *);
+ int (*remove)(void *, struct l9p_fid *);
+ int (*stat)(void *, struct l9p_request *);
+ int (*walk)(void *, struct l9p_request *);
+ int (*write)(void *, struct l9p_request *);
+ int (*wstat)(void *, struct l9p_request *);
+ int (*statfs)(void *, struct l9p_request *);
+ int (*lopen)(void *, struct l9p_request *);
+ int (*lcreate)(void *, struct l9p_request *);
+ int (*symlink)(void *, struct l9p_request *);
+ int (*mknod)(void *, struct l9p_request *);
+ int (*rename)(void *, struct l9p_request *);
+ int (*readlink)(void *, struct l9p_request *);
+ int (*getattr)(void *, struct l9p_request *);
+ int (*setattr)(void *, struct l9p_request *);
+ int (*xattrwalk)(void *, struct l9p_request *);
+ int (*xattrcreate)(void *, struct l9p_request *);
+ int (*xattrread)(void *, struct l9p_request *);
+ int (*xattrwrite)(void *, struct l9p_request *);
+ int (*xattrclunk)(void *, struct l9p_fid *);
+ int (*readdir)(void *, struct l9p_request *);
+ int (*fsync)(void *, struct l9p_request *);
+ int (*lock)(void *, struct l9p_request *);
+ int (*getlock)(void *, struct l9p_request *);
+ int (*link)(void *, struct l9p_request *);
+ int (*mkdir)(void *, struct l9p_request *);
+ int (*renameat)(void *, struct l9p_request *);
+ int (*unlinkat)(void *, struct l9p_request *);
+};
+
+#endif /* LIB9P_BACKEND_H */
Added: vendor/lib9p/dist/backend/fs.c
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ vendor/lib9p/dist/backend/fs.c Wed Apr 29 16:24:32 2020 (r360470)
@@ -0,0 +1,3061 @@
+/*
+ * Copyright 2016 Jakub Klama <jceel at FreeBSD.org>
+ * All rights reserved
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted providing that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/*
+ * Based on libixp code: ©2007-2010 Kris Maglione <maglione.k at Gmail>
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mount.h>
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <dirent.h>
+#include <pwd.h>
+#include <grp.h>
+#include <libgen.h>
+#include <pthread.h>
+#include "../lib9p.h"
+#include "../lib9p_impl.h"
+#include "../fid.h"
+#include "../log.h"
+#include "../rfuncs.h"
+#include "../genacl.h"
+#include "backend.h"
+#include "fs.h"
+
+#if defined(WITH_CASPER)
+ #include <libcasper.h>
+ #include <casper/cap_pwd.h>
+ #include <casper/cap_grp.h>
+#endif
+
+#if defined(__FreeBSD__)
+ #include <sys/param.h>
+ #if __FreeBSD_version >= 1000000
+ #define HAVE_BINDAT
+ #endif
+#endif
+
+#if defined(__FreeBSD__)
+ #define HAVE_BIRTHTIME
+#endif
+
+#if defined(__APPLE__)
+ #include <sys/syscall.h>
+ #include "Availability.h"
+ #define ACL_TYPE_NFS4 ACL_TYPE_EXTENDED
+#endif
+
+struct fs_softc {
+ int fs_rootfd;
+ bool fs_readonly;
+#if defined(WITH_CASPER)
+ cap_channel_t *fs_cappwd;
+ cap_channel_t *fs_capgrp;
+#endif
+};
+
+struct fs_fid {
+ DIR *ff_dir;
+ int ff_dirfd;
+ int ff_fd;
+ int ff_flags;
+ char *ff_name;
+ struct fs_authinfo *ff_ai;
+ pthread_mutex_t ff_mtx;
+ struct l9p_acl *ff_acl; /* cached ACL if any */
+};
+
+#define FF_NO_NFSV4_ACL 0x01 /* don't go looking for NFSv4 ACLs */
+/* FF_NO_POSIX_ACL 0x02 -- not yet */
+
+/*
+ * Our authinfo consists of:
+ *
+ * - a reference count
+ * - a uid
+ * - a gid-set
+ *
+ * The "default" gid is the first gid in the git-set, provided the
+ * set size is at least 1. The set-size may be zero, though.
+ *
+ * Adjustments to the ref-count must be atomic, once it's shared.
+ * It would be nice to use C11 atomics here but they are not common
+ * enough to all systems just yet; for now, we use a mutex.
+ *
+ * Note that some ops (Linux style ones) pass an effective gid for
+ * the op, in which case, that gid may override. To achieve this
+ * effect, permissions testing functions also take an extra gid.
+ * If this gid is (gid_t)-1 it is not used and only the remaining
+ * gids take part.
+ *
+ * The uid may also be (uid_t)-1, meaning "no uid was available
+ * at all at attach time". In this case, new files inherit parent
+ * directory uids.
+ *
+ * The refcount is simply the number of "openfile"s using this
+ * authinfo (so that when the last ref goes away, we can free it).
+ *
+ * There are also master ACL flags (same as in ff_flags).
+ */
+struct fs_authinfo {
+ pthread_mutex_t ai_mtx; /* lock for refcnt */
+ uint32_t ai_refcnt;
+ int ai_flags;
+ uid_t ai_uid;
+ int ai_ngids;
+ gid_t ai_gids[]; /* NB: flexible array member */
+};
+
+/*
+ * We have a global-static mutex for single-threading Tattach
+ * requests, which use getpwnam (and indirectly, getgr* functions)
+ * which are not reentrant.
+ */
+static bool fs_attach_mutex_inited;
+static pthread_mutex_t fs_attach_mutex;
+
+/*
+ * Internal functions (except inline functions).
+ */
+static struct passwd *fs_getpwuid(struct fs_softc *, uid_t, struct r_pgdata *);
+static struct group *fs_getgrgid(struct fs_softc *, gid_t, struct r_pgdata *);
+static int fs_buildname(struct l9p_fid *, char *, char *, size_t);
+static int fs_pdir(struct fs_softc *, struct l9p_fid *, char *, size_t,
+ struct stat *st);
+static int fs_dpf(char *, char *, size_t);
+static int fs_oflags_dotu(int, int *);
+static int fs_oflags_dotl(uint32_t, int *, enum l9p_omode *);
+static int fs_nde(struct fs_softc *, struct l9p_fid *, bool, gid_t,
+ struct stat *, uid_t *, gid_t *);
+static struct fs_fid *open_fid(int, const char *, struct fs_authinfo *, bool);
+static void dostat(struct fs_softc *, struct l9p_stat *, char *,
+ struct stat *, bool dotu);
+static void dostatfs(struct l9p_statfs *, struct statfs *, long);
+static void fillacl(struct fs_fid *ff);
+static struct l9p_acl *getacl(struct fs_fid *ff, int fd, const char *path);
+static void dropacl(struct fs_fid *ff);
+static struct l9p_acl *look_for_nfsv4_acl(struct fs_fid *ff, int fd,
+ const char *path);
+static int check_access(int32_t,
+ struct l9p_acl *, struct stat *, struct l9p_acl *, struct stat *,
+ struct fs_authinfo *, gid_t);
+static void generate_qid(struct stat *, struct l9p_qid *);
+
+static int fs_icreate(void *, struct l9p_fid *, char *, int,
+ bool, mode_t, gid_t, struct stat *);
+static int fs_iopen(void *, struct l9p_fid *, int, enum l9p_omode,
+ gid_t, struct stat *);
+static int fs_imkdir(void *, struct l9p_fid *, char *,
+ bool, mode_t, gid_t, struct stat *);
+static int fs_imkfifo(void *, struct l9p_fid *, char *,
+ bool, mode_t, gid_t, struct stat *);
+static int fs_imknod(void *, struct l9p_fid *, char *,
+ bool, mode_t, dev_t, gid_t, struct stat *);
+static int fs_imksocket(void *, struct l9p_fid *, char *,
+ bool, mode_t, gid_t, struct stat *);
+static int fs_isymlink(void *, struct l9p_fid *, char *, char *,
+ gid_t, struct stat *);
+
+/*
+ * Internal functions implementing backend.
+ */
+static int fs_attach(void *, struct l9p_request *);
+static int fs_clunk(void *, struct l9p_fid *);
+static int fs_create(void *, struct l9p_request *);
+static int fs_open(void *, struct l9p_request *);
+static int fs_read(void *, struct l9p_request *);
+static int fs_remove(void *, struct l9p_fid *);
+static int fs_stat(void *, struct l9p_request *);
+static int fs_walk(void *, struct l9p_request *);
+static int fs_write(void *, struct l9p_request *);
+static int fs_wstat(void *, struct l9p_request *);
+static int fs_statfs(void *, struct l9p_request *);
+static int fs_lopen(void *, struct l9p_request *);
+static int fs_lcreate(void *, struct l9p_request *);
+static int fs_symlink(void *, struct l9p_request *);
+static int fs_mknod(void *, struct l9p_request *);
+static int fs_rename(void *, struct l9p_request *);
+static int fs_readlink(void *, struct l9p_request *);
+static int fs_getattr(void *, struct l9p_request *);
+static int fs_setattr(void *, struct l9p_request *);
+static int fs_xattrwalk(void *, struct l9p_request *);
+static int fs_xattrcreate(void *, struct l9p_request *);
+static int fs_readdir(void *, struct l9p_request *);
+static int fs_fsync(void *, struct l9p_request *);
+static int fs_lock(void *, struct l9p_request *);
+static int fs_getlock(void *, struct l9p_request *);
+static int fs_link(void *, struct l9p_request *);
+static int fs_renameat(void *, struct l9p_request *);
+static int fs_unlinkat(void *, struct l9p_request *);
+static void fs_freefid(void *, struct l9p_fid *);
+
+/*
+ * Convert from 9p2000 open/create mode to Unix-style O_* flags.
+ * This includes 9p2000.u extensions, but not 9p2000.L protocol,
+ * which has entirely different open, create, etc., flag bits.
+ *
+ * The <mode> given here is the one-byte (uint8_t) "mode"
+ * argument to Tcreate or Topen, so it can have at most 8 bits.
+ *
+ * https://swtch.com/plan9port/man/man9/open.html and
+ * http://plan9.bell-labs.com/magic/man2html/5/open
+ * both say:
+ *
+ * The [low two bits of the] mode field determines the
+ * type of I/O ... [I]f mode has the OTRUNC (0x10) bit
+ * set, the file is to be truncated, which requires write
+ * permission ...; if the mode has the ORCLOSE (0x40) bit
+ * set, the file is to be removed when the fid is clunked,
+ * which requires permission to remove the file from its
+ * directory. All other bits in mode should be zero. It
+ * is illegal to write a directory, truncate it, or
+ * attempt to remove it on close.
+ *
+ * 9P2000.u may add ODIRECT (0x80); this is not completely clear.
+ * The fcall.h header defines OCEXEC (0x20) as well, but it makes
+ * no sense to send this to a server. There seem to be no bits
+ * 0x04 and 0x08.
+ *
+ * We always turn on O_NOCTTY since as a server, we never want
+ * to gain a controlling terminal. We always turn on O_NOFOLLOW
+ * for reasons described elsewhere.
+ */
+static int
+fs_oflags_dotu(int mode, int *aflags)
+{
+ int flags;
+#define CONVERT(theirs, ours) \
+ do { \
+ if (mode & (theirs)) { \
+ mode &= ~(theirs); \
+ flags |= ours; \
+ } \
+ } while (0)
+
+ switch (mode & L9P_OACCMODE) {
+
+ case L9P_OREAD:
+ default:
+ flags = O_RDONLY;
+ break;
+
+ case L9P_OWRITE:
+ flags = O_WRONLY;
+ break;
+
+ case L9P_ORDWR:
+ flags = O_RDWR;
+ break;
+
+ case L9P_OEXEC:
+ if (mode & L9P_OTRUNC)
+ return (EINVAL);
+ flags = O_RDONLY;
+ break;
+ }
+
+ flags |= O_NOCTTY | O_NOFOLLOW;
+
+ CONVERT(L9P_OTRUNC, O_TRUNC);
+
+ /*
+ * Now take away some flags locally:
+ * the access mode (already translated)
+ * ORCLOSE - caller only
+ * OCEXEC - makes no sense in server
+ * ODIRECT - not applicable here
+ * If there are any flag bits left after this,
+ * we were unable to translate them. For now, let's
+ * treat this as EINVAL so that we can catch problems.
+ */
+ mode &= ~(L9P_OACCMODE | L9P_ORCLOSE | L9P_OCEXEC | L9P_ODIRECT);
+ if (mode != 0) {
+ L9P_LOG(L9P_INFO,
+ "fs_oflags_dotu: untranslated bits: %#x",
+ (unsigned)mode);
+ return (EINVAL);
+ }
+
+ *aflags = flags;
+ return (0);
+#undef CONVERT
+}
+
+/*
+ * Convert from 9P2000.L (Linux) open mode bits to O_* flags.
+ * See fs_oflags_dotu above.
+ *
+ * Linux currently does not have open-for-exec, but there is a
+ * proposal for it using O_PATH|O_NOFOLLOW, now handled here.
+ *
+ * We may eventually also set L9P_ORCLOSE for L_O_TMPFILE.
+ */
+static int
+fs_oflags_dotl(uint32_t l_mode, int *aflags, enum l9p_omode *ap9)
+{
+ int flags;
+ enum l9p_omode p9;
+#define CLEAR(theirs) l_mode &= ~(uint32_t)(theirs)
+#define CONVERT(theirs, ours) \
+ do { \
+ if (l_mode & (theirs)) { \
+ CLEAR(theirs); \
+ flags |= ours; \
+ } \
+ } while (0)
+
+ /*
+ * Linux O_RDONLY, O_WRONLY, O_RDWR (0,1,2) match BSD/MacOS.
+ */
+ flags = l_mode & O_ACCMODE;
+ if (flags == 3)
+ return (EINVAL);
+ CLEAR(O_ACCMODE);
+
+ if ((l_mode & (L9P_L_O_PATH | L9P_L_O_NOFOLLOW)) ==
+ (L9P_L_O_PATH | L9P_L_O_NOFOLLOW)) {
+ CLEAR(L9P_L_O_PATH | L9P_L_O_NOFOLLOW);
+ p9 = L9P_OEXEC;
+ } else {
+ /*
+ * Slightly dirty, but same dirt, really, as
+ * setting flags from l_mode & O_ACCMODE.
+ */
+ p9 = (enum l9p_omode)flags; /* slightly dirty */
+ }
+
+ /* turn L_O_TMPFILE into L9P_ORCLOSE in *p9? */
+ if (l_mode & L9P_L_O_TRUNC)
+ p9 |= L9P_OTRUNC; /* but don't CLEAR yet */
+
+ flags |= O_NOCTTY | O_NOFOLLOW;
+
+ /*
+ * L_O_CREAT seems to be noise, since we get separate open
+ * and create. But it is actually set sometimes. We just
+ * throw it out here; create ops must set it themselves and
+ * open ops have no permissions bits and hence cannot create.
+ *
+ * L_O_EXCL does make sense on create ops, i.e., we can
+ * take a create op with or without L_O_EXCL. We pass that
+ * through.
+ */
+ CLEAR(L9P_L_O_CREAT);
+ CONVERT(L9P_L_O_EXCL, O_EXCL);
+ CONVERT(L9P_L_O_TRUNC, O_TRUNC);
+ CONVERT(L9P_L_O_DIRECTORY, O_DIRECTORY);
+ CONVERT(L9P_L_O_APPEND, O_APPEND);
+ CONVERT(L9P_L_O_NONBLOCK, O_NONBLOCK);
+
+ /*
+ * Discard these as useless noise at our (server) end.
+ * (NOATIME might be useful but we can only set it on a
+ * per-mount basis.)
+ */
+ CLEAR(L9P_L_O_CLOEXEC);
+ CLEAR(L9P_L_O_DIRECT);
+ CLEAR(L9P_L_O_DSYNC);
+ CLEAR(L9P_L_O_FASYNC);
+ CLEAR(L9P_L_O_LARGEFILE);
+ CLEAR(L9P_L_O_NOATIME);
+ CLEAR(L9P_L_O_NOCTTY);
+ CLEAR(L9P_L_O_NOFOLLOW);
+ CLEAR(L9P_L_O_SYNC);
+
+ if (l_mode != 0) {
+ L9P_LOG(L9P_INFO,
+ "fs_oflags_dotl: untranslated bits: %#x",
+ (unsigned)l_mode);
+ return (EINVAL);
+ }
+
+ *aflags = flags;
+ *ap9 = p9;
+ return (0);
+#undef CLEAR
+#undef CONVERT
+}
+
+static struct passwd *
+fs_getpwuid(struct fs_softc *sc, uid_t uid, struct r_pgdata *pg)
+{
+#if defined(WITH_CASPER)
+ return (r_cap_getpwuid(sc->fs_cappwd, uid, pg));
+#else
+ (void)sc;
+ return (r_getpwuid(uid, pg));
+#endif
+}
+
+static struct group *
+fs_getgrgid(struct fs_softc *sc, gid_t gid, struct r_pgdata *pg)
+{
+#if defined(WITH_CASPER)
+ return (r_cap_getgrgid(sc->fs_capgrp, gid, pg));
+#else
+ (void)sc;
+ return (r_getgrgid(gid, pg));
+#endif
+}
+
+/*
+ * Build full name of file by appending given name to directory name.
+ */
+static int
+fs_buildname(struct l9p_fid *dir, char *name, char *buf, size_t size)
+{
+ struct fs_fid *dirf = dir->lo_aux;
+ size_t dlen, nlen1;
+
+ assert(dirf != NULL);
+ dlen = strlen(dirf->ff_name);
+ nlen1 = strlen(name) + 1; /* +1 for '\0' */
+ if (dlen + 1 + nlen1 > size)
+ return (ENAMETOOLONG);
+ memcpy(buf, dirf->ff_name, dlen);
+ buf[dlen] = '/';
+ memcpy(buf + dlen + 1, name, nlen1);
+ return (0);
+}
+
+/*
+ * Build parent name of file by splitting it off. Return an error
+ * if the given fid represents the root, so that there is no such
+ * parent, or if the discovered parent is not a directory.
+ */
+static int
+fs_pdir(struct fs_softc *sc __unused, struct l9p_fid *fid, char *buf,
+ size_t size, struct stat *st)
+{
+ struct fs_fid *ff;
+ char *path;
+
+ ff = fid->lo_aux;
+ assert(ff != NULL);
+ path = ff->ff_name;
+ path = r_dirname(path, buf, size);
+ if (path == NULL)
+ return (ENAMETOOLONG);
+ if (fstatat(ff->ff_dirfd, path, st, AT_SYMLINK_NOFOLLOW) != 0)
+ return (errno);
+ if (!S_ISDIR(st->st_mode))
+ return (ENOTDIR);
+ return (0);
+}
+
+/*
+ * Like fs_buildname() but for adding a file name to a buffer
+ * already holding a directory name. Essentially does
+ * strcat(dbuf, "/");
+ * strcat(dbuf, fname);
+ * but with size checking and an ENAMETOOLONG error as needed.
+ *
+ * (Think of the function name as "directory plus-equals file".)
+ */
+static int
+fs_dpf(char *dbuf, char *fname, size_t size)
+{
+ size_t dlen, nlen1;
+
+ dlen = strlen(dbuf);
+ nlen1 = strlen(fname) + 1;
+ if (dlen + 1 + nlen1 > size)
+ return (ENAMETOOLONG);
+ dbuf[dlen] = '/';
+ memcpy(dbuf + dlen + 1, fname, nlen1);
+ return (0);
+}
+
+/*
+ * Prepare to create a new directory entry (open with O_CREAT,
+ * mkdir, etc -- any operation that creates a new inode),
+ * operating in parent data <dir>, based on authinfo <ai> and
+ * effective gid <egid>.
+ *
+ * The new entity should be owned by user/group <*nuid, *ngid>,
+ * if it's really a new entity. It will be a directory if isdir.
+ *
+ * Returns an error number if the entry should not be created
+ * (e.g., read-only file system or no permission to write in
+ * parent directory). Always sets *nuid and *ngid on success:
+ * in the worst case, when there is no available ID, this will
+ * use the parent directory's IDs. Fills in <*st> on success.
+ */
+static int
+fs_nde(struct fs_softc *sc, struct l9p_fid *dir, bool isdir, gid_t egid,
+ struct stat *st, uid_t *nuid, gid_t *ngid)
+{
+ struct fs_fid *dirf;
+ struct fs_authinfo *ai;
+ int32_t op;
+ int error;
+
+ if (sc->fs_readonly)
+ return (EROFS);
+ dirf = dir->lo_aux;
+ assert(dirf != NULL);
+ if (fstatat(dirf->ff_dirfd, dirf->ff_name, st,
+ AT_SYMLINK_NOFOLLOW) != 0)
+ return (errno);
+ if (!S_ISDIR(st->st_mode))
+ return (ENOTDIR);
+ dirf = dir->lo_aux;
+ ai = dirf->ff_ai;
+ fillacl(dirf);
+ op = isdir ? L9P_ACE_ADD_SUBDIRECTORY : L9P_ACE_ADD_FILE;
+ error = check_access(op, dirf->ff_acl, st, NULL, NULL, ai, egid);
+ if (error)
+ return (EPERM);
+
+ *nuid = ai->ai_uid != (uid_t)-1 ? ai->ai_uid : st->st_uid;
+ *ngid = egid != (gid_t)-1 ? egid :
+ ai->ai_ngids > 0 ? ai->ai_gids[0] : st->st_gid;
+ return (0);
+}
+
+/*
+ * Allocate new open-file data structure to attach to a fid.
+ *
+ * The new file's authinfo is the same as the old one's, and
+ * we gain a reference.
+ */
+static struct fs_fid *
+open_fid(int dirfd, const char *path, struct fs_authinfo *ai, bool creating)
+{
+ struct fs_fid *ret;
+ uint32_t newcount;
+ int error;
+
+ ret = l9p_calloc(1, sizeof(*ret));
+ error = pthread_mutex_init(&ret->ff_mtx, NULL);
+ if (error) {
+ free(ret);
+ return (NULL);
+ }
+ ret->ff_fd = -1;
+ ret->ff_dirfd = dirfd;
+ ret->ff_name = strdup(path);
+ if (ret->ff_name == NULL) {
+ pthread_mutex_destroy(&ret->ff_mtx);
+ free(ret);
+ return (NULL);
+ }
+ pthread_mutex_lock(&ai->ai_mtx);
+ newcount = ++ai->ai_refcnt;
+ pthread_mutex_unlock(&ai->ai_mtx);
+ /*
+ * If we just incremented the count to 1, we're the *first*
+ * reference. This is only allowed when creating the authinfo,
+ * otherwise it means something has gone wrong. This cannot
+ * catch every bad (re)use of a freed authinfo but it may catch
+ * a few.
+ */
+ assert(newcount > 1 || creating);
+ L9P_LOG(L9P_DEBUG, "authinfo %p now used by %lu",
+ (void *)ai, (u_long)newcount);
+ ret->ff_ai = ai;
+ return (ret);
+}
+
+static void
+dostat(struct fs_softc *sc, struct l9p_stat *s, char *name,
+ struct stat *buf, bool dotu)
+{
+ struct passwd *user;
+ struct group *group;
+
+ memset(s, 0, sizeof(struct l9p_stat));
+
+ generate_qid(buf, &s->qid);
+
+ s->type = 0;
+ s->dev = 0;
+ s->mode = buf->st_mode & 0777;
+
+ if (S_ISDIR(buf->st_mode))
+ s->mode |= L9P_DMDIR;
+
+ if (S_ISLNK(buf->st_mode) && dotu)
+ s->mode |= L9P_DMSYMLINK;
+
+ if (S_ISCHR(buf->st_mode) || S_ISBLK(buf->st_mode))
+ s->mode |= L9P_DMDEVICE;
+
+ if (S_ISSOCK(buf->st_mode))
+ s->mode |= L9P_DMSOCKET;
+
+ if (S_ISFIFO(buf->st_mode))
+ s->mode |= L9P_DMNAMEDPIPE;
+
+ s->atime = (uint32_t)buf->st_atime;
+ s->mtime = (uint32_t)buf->st_mtime;
+ s->length = (uint64_t)buf->st_size;
+
+ s->name = r_basename(name, NULL, 0);
+
+ if (!dotu) {
+ struct r_pgdata udata, gdata;
+
+ user = fs_getpwuid(sc, buf->st_uid, &udata);
+ group = fs_getgrgid(sc, buf->st_gid, &gdata);
+ s->uid = user != NULL ? strdup(user->pw_name) : NULL;
+ s->gid = group != NULL ? strdup(group->gr_name) : NULL;
+ s->muid = user != NULL ? strdup(user->pw_name) : NULL;
+ r_pgfree(&udata);
+ r_pgfree(&gdata);
+ } else {
+ /*
+ * When using 9P2000.u, we don't need to bother about
+ * providing user and group names in textual form.
+ *
+ * NB: if the asprintf()s fail, s->extension should
+ * be unset so we can ignore these.
+ */
+ s->n_uid = buf->st_uid;
+ s->n_gid = buf->st_gid;
+ s->n_muid = buf->st_uid;
+
+ if (S_ISLNK(buf->st_mode)) {
+ char target[MAXPATHLEN];
+ ssize_t ret = readlink(name, target, MAXPATHLEN);
+
+ if (ret < 0) {
+ s->extension = NULL;
+ return;
+ }
+
+ s->extension = strndup(target, (size_t)ret);
+ }
+
+ if (S_ISBLK(buf->st_mode)) {
+ asprintf(&s->extension, "b %d %d", major(buf->st_rdev),
+ minor(buf->st_rdev));
+ }
+
+ if (S_ISCHR(buf->st_mode)) {
+ asprintf(&s->extension, "c %d %d", major(buf->st_rdev),
+ minor(buf->st_rdev));
+ }
*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
More information about the svn-src-all
mailing list