/* $Id: vboxvfs_vfsops.c 44529 2013-02-04 15:54:15Z vboxsync $ */ /** @file * Description. */ /* * Copyright (C) 2008-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; * you can redistribute it and/or modify it under the terms of the GNU * General Public License (GPL) as published by the Free Software * Foundation, in version 2 as it comes in the "COPYING" file of the * VirtualBox OSE distribution. VirtualBox OSE is distributed in the * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. */ #include "vboxvfs.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #define VFSMP2SFGLOBINFO(mp) ((struct sf_glob_info *)mp->mnt_data) static int vboxvfs_version = VBOXVFS_VERSION; SYSCTL_NODE(_vfs, OID_AUTO, vboxvfs, CTLFLAG_RW, 0, "VirtualBox shared filesystem"); SYSCTL_INT(_vfs_vboxvfs, OID_AUTO, version, CTLFLAG_RD, &vboxvfs_version, 0, ""); /* global connection to the host service. */ static VBSFCLIENT g_vboxSFClient; static vfs_init_t vboxvfs_init; static vfs_uninit_t vboxvfs_uninit; static vfs_cmount_t vboxvfs_cmount; static vfs_mount_t vboxvfs_mount; static vfs_root_t vboxvfs_root; static vfs_quotactl_t vboxvfs_quotactl; static vfs_statfs_t vboxvfs_statfs; static vfs_unmount_t vboxvfs_unmount; static struct vfsops vboxvfs_vfsops = { .vfs_init = vboxvfs_init, .vfs_cmount = vboxvfs_cmount, .vfs_mount = vboxvfs_mount, .vfs_quotactl = vboxvfs_quotactl, .vfs_root = vboxvfs_root, .vfs_statfs = vboxvfs_statfs, .vfs_sync = vfs_stdsync, .vfs_uninit = vboxvfs_uninit, .vfs_unmount = vboxvfs_unmount, }; VFS_SET(vboxvfs_vfsops, vboxvfs, VFCF_NETWORK); MODULE_DEPEND(vboxvfs, vboxguest, 1, 1, 1); static int vboxvfs_cmount(struct mntarg *ma, void * data, int flags, struct thread *td) { struct vboxvfs_mount_info args; int rc = 0; printf("%s: Enter\n", __FUNCTION__); rc = copyin(data, &args, sizeof(struct vboxvfs_mount_info)); if (rc) return rc; ma = mount_argf(ma, "uid", "%d", args.uid); ma = mount_argf(ma, "gid", "%d", args.gid); ma = mount_arg(ma, "from", args.name, -1); rc = kernel_mount(ma, flags); printf("%s: Leave rc=%d\n", __FUNCTION__, rc); return rc; } static const char *vboxvfs_opts[] = { "uid", "gid", "from", "fstype", "fspath", "errmsg", NULL }; static int vboxvfs_mount(struct mount *mp, struct thread *td) { int rc; char *pszShare; int cbShare, cbOption; int uid = 0, gid = 0; struct sf_glob_info *pShFlGlobalInfo; SHFLSTRING *pShFlShareName = NULL; int cbShFlShareName; printf("%s: Enter\n", __FUNCTION__); if (mp->mnt_flag & (MNT_UPDATE | MNT_ROOTFS)) return EOPNOTSUPP; if (vfs_filteropt(mp->mnt_optnew, vboxvfs_opts)) { vfs_mount_error(mp, "%s", "Invalid option"); return EINVAL; } rc = vfs_getopt(mp->mnt_optnew, "from", (void **)&pszShare, &cbShare); if (rc || pszShare[cbShare-1] != '\0' || cbShare > 0xfffe) return EINVAL; rc = vfs_getopt(mp->mnt_optnew, "gid", (void **)&gid, &cbOption); if ((rc != ENOENT) && (rc || cbOption != sizeof(gid))) return EINVAL; rc = vfs_getopt(mp->mnt_optnew, "uid", (void **)&uid, &cbOption); if ((rc != ENOENT) && (rc || cbOption != sizeof(uid))) return EINVAL; pShFlGlobalInfo = RTMemAllocZ(sizeof(struct sf_glob_info)); if (!pShFlGlobalInfo) return ENOMEM; cbShFlShareName = offsetof (SHFLSTRING, String.utf8) + cbShare + 1; pShFlShareName = RTMemAllocZ(cbShFlShareName); if (!pShFlShareName) return VERR_NO_MEMORY; pShFlShareName->u16Length = cbShFlShareName; pShFlShareName->u16Size = cbShFlShareName + 1; memcpy (pShFlShareName->String.utf8, pszShare, cbShare + 1); rc = vboxCallMapFolder (&g_vboxSFClient, pShFlShareName, &pShFlGlobalInfo->map); RTMemFree(pShFlShareName); if (RT_FAILURE (rc)) { RTMemFree(pShFlGlobalInfo); printf("vboxCallMapFolder failed rc=%d\n", rc); return EPROTO; } pShFlGlobalInfo->uid = uid; pShFlGlobalInfo->gid = gid; mp->mnt_data = pShFlGlobalInfo; /* @todo root vnode. */ vfs_getnewfsid(mp); vfs_mountedfrom(mp, pszShare); printf("%s: Leave rc=0\n", __FUNCTION__); return 0; } static int vboxvfs_unmount(struct mount *mp, int mntflags, struct thread *td) { struct sf_glob_info *pShFlGlobalInfo = VFSMP2SFGLOBINFO(mp); int rc; int flags = 0; rc = vboxCallUnmapFolder(&g_vboxSFClient, &pShFlGlobalInfo->map); if (RT_FAILURE(rc)) printf("Failed to unmap shared folder\n"); if (mntflags & MNT_FORCE) flags |= FORCECLOSE; /* There is 1 extra root vnode reference (vnode_root). */ rc = vflush(mp, 1, flags, td); if (rc) return rc; RTMemFree(pShFlGlobalInfo); mp->mnt_data = NULL; return 0; } static int vboxvfs_root(struct mount *mp, int flags, struct vnode **vpp, struct thread *td) { int rc = 0; struct sf_glob_info *pShFlGlobalInfo = VFSMP2SFGLOBINFO(mp); struct vnode *vp; printf("%s: Enter\n", __FUNCTION__); vp = pShFlGlobalInfo->vnode_root; VREF(vp); vn_lock(vp, flags | LK_RETRY, td); *vpp = vp; printf("%s: Leave\n", __FUNCTION__); return rc; } static int vboxvfs_quotactl(struct mount *mp, int cmd, uid_t uid, void *arg, struct thread *td) { return EOPNOTSUPP; } int vboxvfs_init(struct vfsconf *vfsp) { int rc; /* Initialize the R0 guest library. */ rc = vboxInit(); if (RT_FAILURE(rc)) return ENXIO; /* Connect to the host service. */ rc = vboxConnect(&g_vboxSFClient); if (RT_FAILURE(rc)) { printf("Failed to get connection to host! rc=%d\n", rc); vboxUninit(); return ENXIO; } rc = vboxCallSetUtf8 (&g_vboxSFClient); if (RT_FAILURE (rc)) { printf("vboxCallSetUtf8 failed, rc=%d\n", rc); vboxDisconnect(&g_vboxSFClient); vboxUninit(); return EPROTO; } printf("Successfully loaded shared folder module\n"); return 0; } int vboxvfs_uninit(struct vfsconf *vfsp) { vboxDisconnect(&g_vboxSFClient); vboxUninit(); return 0; } int vboxvfs_statfs(struct mount *mp, struct statfs *sbp, struct thread *td) { return 0; }