summaryrefslogtreecommitdiffstats
path: root/rtemsbsd/rtems/rtems-kernel-vfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'rtemsbsd/rtems/rtems-kernel-vfs.c')
-rw-r--r--rtemsbsd/rtems/rtems-kernel-vfs.c969
1 files changed, 969 insertions, 0 deletions
diff --git a/rtemsbsd/rtems/rtems-kernel-vfs.c b/rtemsbsd/rtems/rtems-kernel-vfs.c
new file mode 100644
index 00000000..d5729bfb
--- /dev/null
+++ b/rtemsbsd/rtems/rtems-kernel-vfs.c
@@ -0,0 +1,969 @@
+/**
+ * @file
+ *
+ * @ingroup rtems_bsd_rtems
+ *
+ * @brief VFS to RTEMS LibIO interface.
+ */
+
+/*
+ * Copyright (c) 2020 Chris Johns. All rights reserved.
+ *
+ * Contemporary Software
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ */
+
+#include <machine/rtems-bsd-kernel-space.h>
+
+#include <sys/param.h>
+#include <sys/buf.h>
+#include <sys/capsicum.h>
+#include <sys/errno.h>
+#include <sys/fcntl.h>
+#include <sys/file.h>
+#include <sys/filedesc.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/mount.h>
+#include <sys/namei.h>
+#include <sys/proc.h>
+#include <sys/syscallsubr.h>
+#include <sys/sysproto.h>
+#include <sys/time.h>
+#include <sys/vnode.h>
+
+#include <rtems/libio.h>
+#include <rtems/seterr.h>
+
+const rtems_filesystem_operations_table rtems_bsd_vfsops = {
+ .lock_h = rtems_bsd_vfs_mt_entry_lock,
+ .unlock_h = rtems_bsd_vfs_mt_entry_unlock,
+ .eval_path_h = rtems_bsd_vfs_eval_path,
+ .link_h = rtems_bsd_vfs_link,
+ .are_nodes_equal_h = rtems_bsd_vfs_are_nodes_equal,
+ .mknod_h = rtems_bsd_vfs_mknod,
+ .rmnod_h = rtems_bsd_vfs_rmnod,
+ .fchmod_h = rtems_bsd_vfs_fchmod,
+ .chown_h = rtems_bsd_vfs_chown,
+ .clonenod_h = rtems_bsd_vfs_clonenode,
+ .freenod_h = rtems_bsd_vfs_freenode,
+ .mount_h = rtems_bsd_vfs_mount,
+ .unmount_h = rtems_bsd_vfs_unmount,
+ .fsunmount_me_h = rtems_bsd_vfs_fsunmount_me,
+ .utimens_h = rtems_bsd_vfs_utimens,
+ .symlink_h = rtems_bsd_vfs_symlink,
+ .readlink_h = rtems_bsd_vfs_readlink,
+ .rename_h = rtems_bsd_vfs_rename,
+ .statvfs_h = rtems_bsd_vfs_statvfs
+};
+
+int
+rtems_bsd_vfs_mount_init(rtems_filesystem_mount_table_entry_t *mt_entry)
+{
+ mt_entry->fs_info = NULL;
+ mt_entry->no_regular_file_mknod = true;
+ mt_entry->ops = &rtems_bsd_vfsops;
+ mt_entry->mt_fs_root->location.node_access = 0;
+ mt_entry->mt_fs_root->location.handlers = &rtems_bsd_sysgen_dirops;
+ return 0;
+}
+
+static void
+rtems_bsd_vfs_loc_vnode_hold(
+ rtems_filesystem_location_info_t *loc, struct vnode *vp)
+{
+ if (vp != NULL) {
+ VREF(vp);
+ if (RTEMS_BSD_VFS_TRACE)
+ printf("bsd: vfs: loc: hold loc=%p vn=%p\n", loc, vp);
+ }
+}
+
+static void
+rtems_bsd_vfs_loc_vnode_drop(
+ rtems_filesystem_location_info_t *loc, struct vnode *vp)
+{
+ if (vp != NULL) {
+ vrele(vp);
+ if (RTEMS_BSD_VFS_TRACE) {
+ printf("bsd: vfs: loc: drop loc=%p vn=%p\n", loc, vp);
+ }
+ }
+}
+
+static void
+rtems_bsd_vfs_loc_hold(rtems_filesystem_location_info_t *loc)
+{
+ if (loc != NULL) {
+ if (RTEMS_BSD_VFS_TRACE)
+ printf("bsd: vfs: loc: hold loc=%p vn=%p vdp=%p\n", loc,
+ rtems_bsd_libio_loc_to_vnode(loc),
+ rtems_bsd_libio_loc_to_vnode_dir(loc));
+ rtems_bsd_vfs_loc_vnode_hold(
+ loc, rtems_bsd_libio_loc_to_vnode(loc));
+ rtems_bsd_vfs_loc_vnode_hold(
+ loc, rtems_bsd_libio_loc_to_vnode_dir(loc));
+ }
+}
+
+static void
+rtems_bsd_vfs_loc_drop(rtems_filesystem_location_info_t *loc)
+{
+ if (loc != NULL) {
+ if (RTEMS_BSD_VFS_TRACE)
+ printf("bsd: vfs: loc: drop loc=%p vn=%p vdp=%p\n", loc,
+ rtems_bsd_libio_loc_to_vnode(loc),
+ rtems_bsd_libio_loc_to_vnode_dir(loc));
+ rtems_bsd_libio_loc_set_vnode(loc, NULL);
+ rtems_bsd_libio_loc_set_vnode_dir(loc, NULL);
+ }
+}
+
+void
+rtems_bsd_vfs_mt_entry_lock(
+ const rtems_filesystem_mount_table_entry_t *mt_entry)
+{
+ struct vnode *vp = rtems_bsd_libio_loc_to_vnode(
+ &mt_entry->mt_fs_root->location);
+ if (RTEMS_BSD_VFS_TRACE) {
+ printf("bsd: vfs: lock: vn=%p\n", vp);
+ }
+ VREF(vp);
+}
+
+void
+rtems_bsd_vfs_mt_entry_unlock(
+ const rtems_filesystem_mount_table_entry_t *mt_entry)
+{
+ struct vnode *vp = rtems_bsd_libio_loc_to_vnode(
+ &mt_entry->mt_fs_root->location);
+ if (RTEMS_BSD_VFS_TRACE) {
+ printf("bsd: vfs: unlock: vn=%p\n", vp);
+ }
+ vrele(vp);
+}
+
+static void
+rtems_bsd_vfs_componentname(struct componentname *cnd, u_long nameiop,
+ char *name, u_int namelen, struct ucred *cred)
+{
+ memset(cnd, 0, sizeof(*cnd));
+ cnd->cn_nameiop = nameiop;
+ cnd->cn_nameptr = name;
+ cnd->cn_namelen = namelen;
+ cnd->cn_cred = cred;
+}
+
+static int
+rtems_bsd_vfs_vnode_componentname(struct componentname *cnd, struct vnode *vp,
+ u_long nameiop, char *name, u_int namelen, struct ucred *cred)
+{
+ struct vnode *tvp;
+ const u_int namemax = namelen - 1;
+ char *namep;
+ int error;
+ name[namemax] = '\0';
+ namelen = namemax;
+ tvp = vp;
+ error = vn_vptocnp(&tvp, NULL, name, &namelen);
+ if (error == 0) {
+ name = &name[namelen];
+ namelen = namemax - namelen;
+ } else {
+ name = NULL;
+ namelen = 0;
+ }
+ rtems_bsd_vfs_componentname(cnd, nameiop, name, namelen, cred);
+ return error;
+}
+
+static bool
+rtems_bsd_vfs_vnode_is_directory(
+ rtems_filesystem_eval_path_context_t *ctx, void *arg)
+{
+ struct vnode *vp = *((struct vnode **)arg);
+ return vp->v_type == VDIR;
+}
+
+static rtems_filesystem_eval_path_generic_status
+rtems_bsd_vfs_eval_token(rtems_filesystem_eval_path_context_t *ctx, void *arg,
+ const char *token, size_t tokenlen)
+{
+ rtems_filesystem_location_info_t *currentloc;
+ struct thread *td = curthread;
+ struct filedesc *fdp = td->td_proc->p_fd;
+ struct nameidata nd;
+ struct vnode **vpp = arg;
+ struct vnode *vp;
+ struct vnode *dvp;
+ struct vnode *cdir;
+ struct vnode *rdir;
+ char ntoken[NAME_MAX + 1];
+ u_long op = LOOKUP;
+ u_long flags = 0;
+ int eval_flags;
+ bool no_more_path;
+ rtems_filesystem_location_info_t *rootloc;
+ int error;
+
+ currentloc = rtems_filesystem_eval_path_get_currentloc(ctx);
+ no_more_path = !rtems_filesystem_eval_path_has_path(ctx);
+
+ if (RTEMS_BSD_VFS_TRACE) {
+ printf("bsd: vfs: eval_token: t=%s:%d vp=%p\n", token, tokenlen,
+ *vpp);
+ }
+
+ if (tokenlen > NAME_MAX) {
+ rtems_filesystem_eval_path_error(ctx, E2BIG);
+ return RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_DONE;
+ }
+
+ if (rtems_filesystem_is_current_directory(token, tokenlen)) {
+ rtems_filesystem_eval_path_clear_token(ctx);
+ return no_more_path ?
+ RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_DONE :
+ RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_CONTINUE;
+ }
+
+ /*
+ * Have we reached the root vnode. Note the namei call will
+ * successfully lookup `..` when we are at the mount point
+ * because VFS mounts are held under the root pseudofs file
+ * system.
+ */
+ rootloc = &currentloc->mt_entry->mt_fs_root->location;
+ if (*vpp == rtems_bsd_libio_loc_to_vnode(rootloc)) {
+ if (rtems_filesystem_is_parent_directory(token, tokenlen)) {
+ if (RTEMS_BSD_VFS_TRACE) {
+ printf(
+ "bsd: vfs: parent from root: vp=%p rvp=%p\n",
+ *vpp,
+ rtems_bsd_libio_loc_to_vnode(rootloc));
+ }
+ rtems_filesystem_eval_path_put_back_token(ctx);
+ return RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_CONTINUE;
+ }
+ }
+
+ eval_flags = rtems_filesystem_eval_path_get_flags(ctx);
+ flags |= (eval_flags & RTEMS_FS_FOLLOW_LINK) != 0 ? FOLLOW : NOFOLLOW;
+
+ if (no_more_path && ((eval_flags & RTEMS_FS_MAKE) != 0)) {
+ op = CREATE;
+ flags |= LOCKPARENT;
+ }
+
+ flags |= WANTPARENT;
+
+ FILEDESC_XLOCK(fdp);
+ rdir = fdp->fd_rdir;
+ cdir = fdp->fd_cdir;
+ fdp->fd_rdir = rootvnode;
+ fdp->fd_cdir = *vpp;
+ vref(*vpp);
+ FILEDESC_XUNLOCK(fdp);
+
+ bcopy(token, ntoken, tokenlen);
+ ntoken[tokenlen] = '\0';
+
+ NDINIT_ATVP(&nd, op, flags, UIO_USERSPACE, ntoken, *vpp, td);
+ error = namei(&nd);
+
+ if (RTEMS_BSD_VFS_TRACE) {
+ printf(
+ "bsd: vfs: eval_token: namei=%d:%s token=%s cwd=%p vp=%p dvp=%p mp=%p %s\n",
+ error, strerror(error), ntoken, *vpp, nd.ni_vp, nd.ni_dvp,
+ nd.ni_vp ? nd.ni_vp->v_mountedhere : NULL,
+ no_more_path ? "no-more-path" : "more-path");
+ }
+
+ if (error != 0) {
+ NDFREE(&nd, NDF_ONLY_PNBUF);
+ rtems_filesystem_eval_path_error(ctx, error);
+ return RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_DONE;
+ }
+
+ FILEDESC_XLOCK(fdp);
+ fdp->fd_rdir = rdir;
+ fdp->fd_cdir = cdir;
+ FILEDESC_XUNLOCK(fdp);
+
+ /*
+ * If there is no more path and this is the last token and the lookup
+ * with CREATE failed to find a vnode it does not exist and needs to be
+ * created. Leave the currentloc where it is.
+ */
+ if (nd.ni_vp != NULL) {
+ rtems_bsd_libio_loc_set_vnode(currentloc, nd.ni_vp);
+ rtems_bsd_libio_loc_set_vnode_dir(currentloc, nd.ni_dvp);
+ }
+
+ *vpp = nd.ni_vp;
+
+ NDFREE(&nd, 0);
+
+ if (*vpp == rtems_bsd_libio_loc_to_vnode(rootloc)) {
+ if (RTEMS_BSD_VFS_TRACE) {
+ printf(
+ "bsd: vfs: eval_token: cross-mount vp=%p rvp=%p\n",
+ *vpp, rtems_bsd_libio_loc_to_vnode(rootloc));
+ }
+ rtems_filesystem_eval_path_clear_token(ctx);
+ return RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_CONTINUE;
+ }
+
+ if (*vpp != NULL) {
+ rtems_filesystem_eval_path_clear_token(ctx);
+ }
+
+ return no_more_path ? RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_DONE :
+ RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_CONTINUE;
+}
+
+static const rtems_filesystem_eval_path_generic_config
+ rtems_bsd_vfs_eval_config = {
+ .is_directory = rtems_bsd_vfs_vnode_is_directory,
+ .eval_token = rtems_bsd_vfs_eval_token
+ };
+
+void
+rtems_bsd_vfs_eval_path(rtems_filesystem_eval_path_context_t *ctx)
+{
+ rtems_filesystem_location_info_t *currentloc;
+ struct vnode *vp;
+
+ errno = 0;
+
+ currentloc = rtems_filesystem_eval_path_get_currentloc(ctx);
+ vp = rtems_bsd_libio_loc_to_vnode(currentloc);
+
+ if (RTEMS_BSD_VFS_TRACE) {
+ printf("bsd: vfs: eval_path: t=%s:%d (%s) cloc=%p\n",
+ ctx->token, ctx->tokenlen, ctx->path, vp);
+ }
+
+ /*
+ * For locking
+ */
+ rtems_bsd_libio_loc_set_vnode(currentloc, vp);
+ rtems_bsd_libio_loc_set_vnode_dir(currentloc, vp);
+
+ rtems_filesystem_eval_path_generic(
+ ctx, &vp, &rtems_bsd_vfs_eval_config);
+
+ if (RTEMS_BSD_VFS_TRACE) {
+ printf("bsd: vfs: eval_path: e=%d:%s vp=%p cloc=%p lookup=%p\n",
+ errno, strerror(errno), vp,
+ rtems_bsd_libio_loc_to_vnode(currentloc),
+ rtems_bsd_libio_loc_to_vnode_dir(currentloc));
+ }
+}
+
+bool
+rtems_bsd_vfs_are_nodes_equal(const rtems_filesystem_location_info_t *a,
+ const rtems_filesystem_location_info_t *b)
+{
+ struct vnode *avp = rtems_bsd_libio_loc_to_vnode(a);
+ struct vnode *bvp = rtems_bsd_libio_loc_to_vnode(b);
+ struct vnode *advp = rtems_bsd_libio_loc_to_vnode_dir(a);
+ struct vnode *bdvp = rtems_bsd_libio_loc_to_vnode_dir(b);
+ bool eq;
+ if (advp != NULL && bdvp != NULL) {
+ eq = avp == bvp && advp == bdvp;
+ } else {
+ eq = avp == bvp;
+ }
+ if (RTEMS_BSD_VFS_TRACE) {
+ printf(
+ "bsd: vfs: nodes_equal: %s vn:%s (%p == %p) dvn:%s (%p == %p)\n",
+ eq ? "EQ" : "NE", avp == bvp ? "equal" : "not-equal", avp,
+ bvp, advp == bdvp ? "equal" : "not-equal", advp, bdvp);
+ }
+ return eq;
+}
+
+int
+rtems_bsd_vfs_clonenode(rtems_filesystem_location_info_t *loc)
+{
+ rtems_bsd_vfs_loc_hold(loc);
+ if (RTEMS_BSD_VFS_TRACE) {
+ struct vnode *vp = rtems_bsd_libio_loc_to_vnode(loc);
+ struct vnode *dvp = rtems_bsd_libio_loc_to_vnode_dir(loc);
+ printf("bsd: vfs: clonenode: %p vn=%p dvp=%p\n", loc, vp, dvp);
+ }
+ return 0;
+}
+
+void
+rtems_bsd_vfs_freenode(const rtems_filesystem_location_info_t *loc)
+{
+ if (RTEMS_BSD_VFS_TRACE) {
+ struct vnode *vp = rtems_bsd_libio_loc_to_vnode(loc);
+ struct vnode *dp = rtems_bsd_libio_loc_to_vnode_dir(loc);
+ printf("bsd: vfs: freenode: %p vn=%p dp=%p\n", loc, vp, dp);
+ }
+ rtems_bsd_vfs_loc_drop(
+ RTEMS_DECONST(rtems_filesystem_location_info_t *, loc));
+}
+
+int
+rtems_bsd_vfs_link(const rtems_filesystem_location_info_t *targetdirloc,
+ const rtems_filesystem_location_info_t *sourceloc, const char *name,
+ size_t namelen)
+{
+ struct thread *td = curthread;
+ struct mount *mp;
+ struct vnode *tdvp = rtems_bsd_libio_loc_to_vnode(targetdirloc);
+ struct vnode *svp = rtems_bsd_libio_loc_to_vnode(sourceloc);
+ struct componentname cn;
+ int error;
+ if (RTEMS_BSD_VFS_TRACE) {
+ printf(
+ "bsd: vfs: link tdvn=%p svn=%p name=%s\n", tdvp, svp, name);
+ }
+ if (td == NULL) {
+ if (RTEMS_BSD_VFS_TRACE) {
+ printf("bsd: vfs: link: no curthread\n");
+ }
+ return rtems_bsd_error_to_status_and_errno(ENOMEM);
+ }
+ if (svp->v_mount != tdvp->v_mount) {
+ if (RTEMS_BSD_VFS_TRACE)
+ printf("bsd: vfs: link: crossmounts\n");
+ error = EXDEV;
+ goto out;
+ }
+ vref(tdvp);
+ vn_lock(tdvp, LK_EXCLUSIVE | LK_RETRY);
+ error = vn_start_write(tdvp, &mp, V_NOWAIT);
+ if (error != 0) {
+ vput(tdvp);
+ error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH);
+ if (error == 0)
+ error = EAGAIN;
+ goto out;
+ }
+ rtems_bsd_vfs_componentname(
+ &cn, LOOKUP, RTEMS_DECONST(char *, name), namelen, td->td_ucred);
+ error = VOP_LINK(tdvp, svp, &cn);
+ VOP_UNLOCK(tdvp, 0);
+out:
+ return rtems_bsd_error_to_status_and_errno(error);
+}
+
+int
+rtems_bsd_vfs_fchmod(const rtems_filesystem_location_info_t *loc, mode_t mode)
+{
+ struct thread *td = rtems_bsd_get_curthread_or_null();
+ struct vnode *vp = rtems_bsd_libio_loc_to_vnode(loc);
+ int error;
+ if (RTEMS_BSD_VFS_TRACE) {
+ printf("bsd: vfs: fchmod: vn=%p mode=%x\n", vp, mode);
+ }
+ if (td == NULL) {
+ if (RTEMS_BSD_VFS_TRACE) {
+ printf("bsd: vfs: fchmod: no curthread\n");
+ }
+ return rtems_bsd_error_to_status_and_errno(ENOMEM);
+ }
+ error = setfmode(td, NULL, vp, mode);
+ return rtems_bsd_error_to_status_and_errno(error);
+}
+
+int
+rtems_bsd_vfs_chown(
+ const rtems_filesystem_location_info_t *loc, uid_t owner, gid_t group)
+{
+ struct thread *td = rtems_bsd_get_curthread_or_null();
+ struct vnode *vp = rtems_bsd_libio_loc_to_vnode(loc);
+ int error;
+ if (RTEMS_BSD_VFS_TRACE) {
+ printf("bsd: vfs: chown: vn=%p owner=%d group=%d\n", vp, owner,
+ group);
+ }
+ if (td == NULL) {
+ if (RTEMS_BSD_VFS_TRACE) {
+ printf("bsd: vfs: chown: no curthread\n");
+ }
+ return rtems_bsd_error_to_status_and_errno(ENOMEM);
+ }
+ error = setfown(td, NULL, vp, owner, group);
+ return rtems_bsd_error_to_status_and_errno(error);
+}
+
+int
+rtems_bsd_vfs_mount(rtems_filesystem_mount_table_entry_t *mt_entry)
+{
+ int error;
+ if (RTEMS_BSD_VFS_TRACE) {
+ printf("bsd: vfs: mount\n");
+ }
+ error = EOPNOTSUPP;
+ return rtems_bsd_error_to_status_and_errno(error);
+}
+
+int
+rtems_bsd_vfs_fsmount_me(
+ rtems_filesystem_mount_table_entry_t *mt_entry, const void *data)
+{
+ struct thread *td = curthread;
+ struct mount_args *args = (struct mount_args *)data;
+ int error;
+ if (RTEMS_BSD_VFS_TRACE) {
+ printf("bsd: vfs: fsmount_me\n");
+ }
+ if (td == NULL) {
+ if (RTEMS_BSD_VFS_TRACE) {
+ printf("bsd: vfs: fsmount_me: no curthread\n");
+ }
+ return rtems_bsd_error_to_status_and_errno(ENOMEM);
+ }
+ error = sys_mount(td, args);
+ if (RTEMS_BSD_VFS_TRACE) {
+ printf("bsd: vfs: fsmount_me: error=%d %s\n", error,
+ strerror(error));
+ }
+ return rtems_bsd_error_to_status_and_errno(error);
+}
+
+int
+rtems_bsd_vfs_unmount(rtems_filesystem_mount_table_entry_t *mt_entry)
+{
+ int error;
+ if (RTEMS_BSD_VFS_TRACE) {
+ printf("bsd: vfs: unmount\n");
+ }
+ error = EOPNOTSUPP;
+ return rtems_bsd_error_to_status_and_errno(error);
+}
+
+void
+rtems_bsd_vfs_fsunmount_me(rtems_filesystem_mount_table_entry_t *mt_entry)
+{
+ int error;
+ if (RTEMS_BSD_VFS_TRACE) {
+ printf("bsd: vfs: fsunmount_me: %p\n",
+ rtems_bsd_libio_loc_to_vnode(
+ &mt_entry->mt_fs_root->location));
+ }
+ rtems_bsd_vfs_loc_drop(&mt_entry->mt_fs_root->location);
+}
+
+int
+rtems_bsd_vfs_mknod(const rtems_filesystem_location_info_t *parentloc,
+ const char *name, size_t namelen, mode_t mode, dev_t dev)
+{
+ struct thread *td = curthread;
+ struct filedesc *fdp = td->td_proc->p_fd;
+ struct vnode *vn = rtems_bsd_libio_loc_to_vnode(parentloc);
+ char *path = RTEMS_DECONST(char *, name);
+ int error;
+
+ if (td == NULL) {
+ if (RTEMS_BSD_VFS_TRACE) {
+ printf("bsd: vfs: mknod: no curthread\n");
+ }
+ return rtems_bsd_error_to_status_and_errno(ENOMEM);
+ }
+
+ if (RTEMS_BSD_VFS_TRACE) {
+ const char *type;
+ if ((mode & S_IFMT) == S_IFREG)
+ type = "REG";
+ else if ((mode & S_IFMT) == S_IFDIR)
+ type = "DIR";
+ else
+ type = "DEV";
+ printf(
+ "bsd: vfs: mknod: mode=%s name=%s (%d) mode=%08x dev=%08llx parent=%p\n",
+ type, name, namelen, mode, dev, vn);
+ }
+
+ fdp->fd_cdir = vn;
+
+ switch (mode & S_IFMT) {
+ case S_IFREG:
+ error = 0;
+ break;
+ case S_IFDIR:
+ VREF(vn);
+ error = kern_mkdirat(td, AT_FDCWD, path, UIO_USERSPACE, mode);
+ vrele(vn);
+ break;
+ default:
+ VREF(vn);
+ error = kern_mknodat(
+ td, AT_FDCWD, path, UIO_USERSPACE, mode, dev);
+ vrele(vn);
+ break;
+ }
+
+ if (RTEMS_BSD_VFS_TRACE) {
+ printf(
+ "bsd: vfs: mknod: error=%s (%d)\n", strerror(error), error);
+ }
+
+ return rtems_bsd_error_to_status_and_errno(error);
+}
+
+int
+rtems_bsd_vfs_rmnod(const rtems_filesystem_location_info_t *parentloc,
+ const rtems_filesystem_location_info_t *loc)
+{
+ struct thread *td = curthread;
+ struct mount *mp;
+ struct vnode *vp = rtems_bsd_libio_loc_to_vnode(loc);
+ struct vnode *dvp = rtems_bsd_libio_loc_to_vnode(parentloc);
+ struct vnode *tvp;
+ struct componentname cn;
+ char name[255];
+ int error;
+ if (RTEMS_BSD_VFS_TRACE) {
+ printf("bsd: vfs: rmnod vn=%p at=%p\n", vp, dvp);
+ }
+ if (td == NULL) {
+ if (RTEMS_BSD_VFS_TRACE) {
+ printf("bsd: vfs: rmnod: no curthread\n");
+ }
+ return rtems_bsd_error_to_status_and_errno(ENOMEM);
+ }
+ error = rtems_bsd_vfs_vnode_componentname(
+ &cn, vp, DELETE, name, sizeof(name), td->td_ucred);
+ if (error != 0) {
+ if (RTEMS_BSD_VFS_TRACE) {
+ printf(
+ "bsd: vfs: rmnod: componentname lookup: (%d) %s\n",
+ error, strerror(error));
+ }
+ goto out;
+ }
+ if (RTEMS_BSD_VFS_TRACE) {
+ printf("bsd: vfs: rmnod name=%s\n", cn.cn_nameptr);
+ }
+ vref(vp);
+restart:
+ bwillwrite();
+ if (vp->v_vflag & VV_ROOT) {
+ error = EBUSY;
+ goto out;
+ }
+ if (vn_start_write(dvp, &mp, V_NOWAIT) != 0) {
+ if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) !=
+ 0) {
+ return rtems_bsd_error_to_status_and_errno(error);
+ }
+ goto restart;
+ }
+ vfs_notify_upper(vp, VFS_NOTIFY_UPPER_UNLINK);
+ error = VOP_RMDIR(dvp, vp, &cn);
+ vn_finished_write(mp);
+out:
+ return rtems_bsd_error_to_status_and_errno(error);
+}
+
+int
+rtems_bsd_vfs_utimens(
+ const rtems_filesystem_location_info_t *loc, time_t actime, time_t modtime)
+{
+ int error;
+ if (RTEMS_BSD_VFS_TRACE) {
+ printf("bsd: vfs: utimens\n");
+ }
+ error = EOPNOTSUPP;
+ return rtems_bsd_error_to_status_and_errno(error);
+}
+
+int
+rtems_bsd_vfs_symlink(const rtems_filesystem_location_info_t *targetdirloc,
+ const char *name, size_t namelen, const char *target)
+{
+ struct thread *td = curthread;
+ struct filedesc *fdp;
+ struct mount *mp;
+ struct vnode *tdvp = rtems_bsd_libio_loc_to_vnode(targetdirloc);
+ struct vattr vattr;
+ struct nameidata nd;
+ int error;
+ if (RTEMS_BSD_VFS_TRACE) {
+ printf("bsd: vfs: symlink tdvn=%p name=%s target=%s\n", tdvp,
+ name, target);
+ }
+ if (td == NULL) {
+ if (RTEMS_BSD_VFS_TRACE) {
+ printf("bsd: vfs: symlink: no curthread\n");
+ }
+ return rtems_bsd_error_to_status_and_errno(ENOMEM);
+ }
+ fdp = td->td_proc->p_fd;
+ fdp->fd_cdir = tdvp;
+restart:
+ bwillwrite();
+ NDINIT_ATRIGHTS(&nd, CREATE,
+ LOCKPARENT | SAVENAME | AUDITVNODE1 | NOCACHE, UIO_SYSSPACE, name,
+ AT_FDCWD, &cap_symlinkat_rights, td);
+ error = namei(&nd);
+ if (error != 0) {
+ goto out;
+ }
+ if (nd.ni_vp != NULL) {
+ NDFREE(&nd, NDF_ONLY_PNBUF);
+ if (nd.ni_vp == nd.ni_dvp)
+ vrele(nd.ni_dvp);
+ else
+ vput(nd.ni_dvp);
+ vrele(nd.ni_vp);
+ error = EEXIST;
+ goto out;
+ }
+ error = vn_start_write(nd.ni_dvp, &mp, V_NOWAIT);
+ if (error != 0) {
+ NDFREE(&nd, NDF_ONLY_PNBUF);
+ vput(nd.ni_dvp);
+ error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH);
+ if (error != 0) {
+ goto out;
+ }
+ goto restart;
+ }
+ VATTR_NULL(&vattr);
+ vattr.va_mode = ACCESSPERMS & ~td->td_proc->p_fd->fd_cmask;
+ error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr,
+ RTEMS_DECONST(char *, target));
+ if (error != 0) {
+ goto out;
+ }
+ NDFREE(&nd, NDF_ONLY_PNBUF);
+ vput(nd.ni_dvp);
+ vn_finished_write(mp);
+out:
+ return rtems_bsd_error_to_status_and_errno(error);
+}
+
+ssize_t
+rtems_bsd_vfs_readlink(
+ const rtems_filesystem_location_info_t *loc, char *buf, size_t bufsize)
+{
+ struct thread *td = curthread;
+ struct vnode *vp = rtems_bsd_libio_loc_to_vnode(loc);
+ struct iovec aiov;
+ struct uio auio;
+ int error;
+ if (RTEMS_BSD_VFS_TRACE) {
+ printf("bsd: vfs: readlink vn=%p\n", vp);
+ }
+ if (td == NULL) {
+ if (RTEMS_BSD_VFS_TRACE) {
+ printf("bsd: vfs: readlink: no curthread\n");
+ }
+ return rtems_bsd_error_to_status_and_errno(ENOMEM);
+ }
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
+ if (vp->v_type != VLNK && (vp->v_vflag & VV_READLINK) == 0) {
+ error = EINVAL;
+ goto out;
+ }
+ aiov.iov_base = buf;
+ aiov.iov_len = bufsize;
+ auio.uio_iov = &aiov;
+ auio.uio_iovcnt = 1;
+ auio.uio_offset = 0;
+ auio.uio_rw = UIO_READ;
+ auio.uio_segflg = UIO_SYSSPACE;
+ auio.uio_td = td;
+ auio.uio_resid = bufsize;
+ error = VOP_READLINK(vp, &auio, td->td_ucred);
+ td->td_retval[0] = bufsize - auio.uio_resid;
+out:
+ VOP_UNLOCK(vp, 0);
+ return rtems_bsd_error_to_status_and_errno(error);
+}
+
+int
+rtems_bsd_vfs_rename(const rtems_filesystem_location_info_t *oldparentloc,
+ const rtems_filesystem_location_info_t *oldloc,
+ const rtems_filesystem_location_info_t *newparentloc, const char *name,
+ size_t namelen)
+{
+ struct thread *td = curthread;
+ struct mount *mp;
+ struct vnode *olddvp = rtems_bsd_libio_loc_to_vnode(oldparentloc);
+ struct vnode *oldvp = rtems_bsd_libio_loc_to_vnode(oldloc);
+ struct vnode *newdvp = rtems_bsd_libio_loc_to_vnode(newparentloc);
+ struct vnode *fvp;
+ struct vnode *tdvp;
+ struct vnode *tvp;
+ struct nameidata fromnd;
+ struct nameidata tond;
+ struct componentname cn;
+ char fromname[255];
+ int error;
+ if (RTEMS_BSD_VFS_TRACE) {
+ printf("bsd: vfs: rename from=%p/%p to=%p/%s\n", olddvp, oldvp,
+ newdvp, name);
+ }
+ if (td == NULL) {
+ if (RTEMS_BSD_VFS_TRACE) {
+ printf("bsd: vfs: rename: no curthread\n");
+ }
+ return rtems_bsd_error_to_status_and_errno(ENOMEM);
+ }
+ error = rtems_bsd_vfs_vnode_componentname(
+ &cn, oldvp, DELETE, fromname, sizeof(fromname), td->td_ucred);
+ if (error != 0) {
+ if (RTEMS_BSD_VFS_TRACE) {
+ printf(
+ "bsd: vfs: rename: componentname lookup: %p: (%d) %s\n",
+ oldvp, error, strerror(error));
+ }
+ goto out2;
+ }
+ if (RTEMS_BSD_VFS_TRACE) {
+ printf("bsd: vfs: rename fromname=%s\n", cn.cn_nameptr);
+ }
+again:
+ bwillwrite();
+ NDINIT_ATVP(&fromnd, DELETE, WANTPARENT | SAVESTART | AUDITVNODE1,
+ UIO_SYSSPACE, cn.cn_nameptr, olddvp, td);
+ error = namei(&fromnd);
+ if (error != 0) {
+ goto out2;
+ }
+ fvp = fromnd.ni_vp;
+ NDINIT_ATVP(&tond, RENAME,
+ LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART | AUDITVNODE2,
+ UIO_SYSSPACE, name, newdvp, td);
+ if (fromnd.ni_vp->v_type == VDIR)
+ tond.ni_cnd.cn_flags |= WILLBEDIR;
+ error = namei(&tond);
+ if (error != 0) {
+ /* Translate error code for rename("dir1", "dir2/."). */
+ if (error == EISDIR && fvp->v_type == VDIR)
+ error = EINVAL;
+ NDFREE(&fromnd, NDF_ONLY_PNBUF);
+ vrele(fromnd.ni_dvp);
+ vrele(fvp);
+ goto out1;
+ }
+ tdvp = tond.ni_dvp;
+ tvp = tond.ni_vp;
+ error = vn_start_write(fvp, &mp, V_NOWAIT);
+ if (error != 0) {
+ NDFREE(&fromnd, NDF_ONLY_PNBUF);
+ NDFREE(&tond, NDF_ONLY_PNBUF);
+ if (tvp != NULL)
+ vput(tvp);
+ if (tdvp == tvp)
+ vrele(tdvp);
+ else
+ vput(tdvp);
+ vrele(fromnd.ni_dvp);
+ vrele(fvp);
+ vrele(tond.ni_startdir);
+ if (fromnd.ni_startdir != NULL)
+ vrele(fromnd.ni_startdir);
+ error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH);
+ if (error != 0)
+ return (error);
+ goto again;
+ }
+ if (tvp != NULL) {
+ if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
+ error = ENOTDIR;
+ goto out;
+ } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
+ error = EISDIR;
+ goto out;
+ }
+ }
+ if (fvp == tdvp) {
+ error = EINVAL;
+ goto out;
+ }
+out:
+ if (error == 0) {
+ error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
+ tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
+ NDFREE(&fromnd, NDF_ONLY_PNBUF);
+ NDFREE(&tond, NDF_ONLY_PNBUF);
+ } else {
+ NDFREE(&fromnd, NDF_ONLY_PNBUF);
+ NDFREE(&tond, NDF_ONLY_PNBUF);
+ if (tvp != NULL)
+ vput(tvp);
+ if (tdvp == tvp)
+ vrele(tdvp);
+ else
+ vput(tdvp);
+ vrele(fromnd.ni_dvp);
+ vrele(fvp);
+ }
+ vrele(tond.ni_startdir);
+ vn_finished_write(mp);
+out1:
+ if (fromnd.ni_startdir)
+ vrele(fromnd.ni_startdir);
+ if (error == -1)
+ error = 0;
+out2:
+ return rtems_bsd_error_to_status_and_errno(error);
+}
+
+int
+rtems_bsd_vfs_statvfs(
+ const rtems_filesystem_location_info_t *loc, struct statvfs *buf)
+{
+ struct thread *td = curthread;
+ struct vnode *vp = rtems_bsd_libio_loc_to_vnode(loc);
+ struct statfs *sp;
+ struct mount *mp;
+ int error;
+ if (RTEMS_BSD_VFS_TRACE) {
+ printf("bsd: vfs: statvfs\n");
+ }
+ if (td == NULL) {
+ if (RTEMS_BSD_VFS_TRACE) {
+ printf("bsd: vfs: statvfs: no curthread\n");
+ }
+ return rtems_bsd_error_to_status_and_errno(ENOMEM);
+ }
+ mp = vp->v_mount;
+ sp = &mp->mnt_stat;
+ sp->f_version = STATFS_VERSION;
+ sp->f_namemax = NAME_MAX;
+ sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
+ error = VFS_STATFS(mp, sp);
+ if (error == 0) {
+ buf->f_bsize = sp->f_bsize;
+ buf->f_frsize = sp->f_bsize;
+ buf->f_blocks = sp->f_blocks;
+ buf->f_bfree = sp->f_bfree;
+ buf->f_bavail = sp->f_bavail;
+ buf->f_files = sp->f_files;
+ buf->f_ffree = sp->f_ffree;
+ buf->f_fsid = sp->f_fsid.val[0];
+ buf->f_flag = sp->f_flags;
+ buf->f_namemax = sp->f_namemax;
+ }
+ return rtems_bsd_error_to_status_and_errno(error);
+}