vboxvfs_vfsops.c revision 887dfcedd826364b6159847dbd25800c0eeede4a
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller/* $Id$ */
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller/** @file
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller * Description.
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller */
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller/*
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller * Copyright (C) 2008 Sun Microsystems Inc.
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller *
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller * This file is part of VirtualBox Open Source Edition (OSE), as
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller * available from http://www.virtualbox.org. This file is free software;
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller * you can redistribute it and/or modify it under the terms of the GNU
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller * General Public License (GPL) as published by the Free Software
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller * Foundation, in version 2 as it comes in the "COPYING" file of the
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller */
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller#include "vboxvfs.h"
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller#include <sys/param.h>
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller#include <sys/systm.h>
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller#include <sys/proc.h>
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller#include <sys/bio.h>
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller#include <sys/buf.h>
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller#include <sys/kernel.h>
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller#include <sys/sysctl.h>
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller#include <sys/vnode.h>
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller#include <sys/mount.h>
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller#include <sys/stat.h>
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller#include <sys/malloc.h>
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller#include <sys/module.h>
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller#include <iprt/mem.h>
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller#define VFSMP2SFGLOBINFO(mp) ((struct sf_glob_info *)mp->mnt_data)
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmillerstatic int vboxvfs_version = VBOXVFS_VERSION;
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan MmillerSYSCTL_NODE(_vfs, OID_AUTO, vboxvfs, CTLFLAG_RW, 0, "VirtualBox shared filesystem");
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan MmillerSYSCTL_INT(_vfs_vboxvfs, OID_AUTO, version, CTLFLAG_RD, &vboxvfs_version, 0, "");
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller/* global connection to the host service. */
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmillerstatic VBSFCLIENT g_vboxSFClient;
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmillerstatic vfs_init_t vboxvfs_init;
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmillerstatic vfs_uninit_t vboxvfs_uninit;
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmillerstatic vfs_cmount_t vboxvfs_cmount;
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmillerstatic vfs_mount_t vboxvfs_mount;
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmillerstatic vfs_root_t vboxvfs_root;
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmillerstatic vfs_quotactl_t vboxvfs_quotactl;
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmillerstatic vfs_statfs_t vboxvfs_statfs;
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmillerstatic vfs_unmount_t vboxvfs_unmount;
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmillerstatic struct vfsops vboxvfs_vfsops = {
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller .vfs_init = vboxvfs_init,
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller .vfs_cmount = vboxvfs_cmount,
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller .vfs_mount = vboxvfs_mount,
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller .vfs_quotactl = vboxvfs_quotactl,
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller .vfs_root = vboxvfs_root,
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller .vfs_statfs = vboxvfs_statfs,
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller .vfs_sync = vfs_stdsync,
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller .vfs_uninit = vboxvfs_uninit,
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller .vfs_unmount = vboxvfs_unmount,
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller};
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan MmillerVFS_SET(vboxvfs_vfsops, vboxvfs, VFCF_NETWORK);
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan MmillerMODULE_DEPEND(vboxvfs, vboxguest, 1, 1, 1);
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmillerstatic int
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmillervboxvfs_cmount(struct mntarg *ma, void * data, int flags, struct thread *td)
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller{
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller struct vboxvfs_mount_info args;
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller int rc = 0;
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller printf("%s: Enter\n", __FUNCTION__);
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller rc = copyin(data, &args, sizeof(struct vboxvfs_mount_info));
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller if (rc)
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller return rc;
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller ma = mount_argf(ma, "uid", "%d", args.uid);
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller ma = mount_argf(ma, "gid", "%d", args.gid);
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller ma = mount_arg(ma, "from", args.name, -1);
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller rc = kernel_mount(ma, flags);
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller 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 (VBOX_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 (VBOX_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(mp, cmd, uid, arg, td)
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 (VBOX_FAILURE(rc))
return ENXIO;
/* Connect to the host service. */
rc = vboxConnect(&g_vboxSFClient);
if (VBOX_FAILURE(rc))
{
printf("Failed to get connection to host! rc=%d\n", rc);
vboxUninit();
return ENXIO;
}
rc = vboxCallSetUtf8 (&g_vboxSFClient);
if (VBOX_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;
}